From f287e592c05058423ab0873cbd3d9fdf2b9ad85f Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 3 Dec 2020 18:40:51 +0800 Subject: [PATCH 01/83] Add Autofac.Extensions.DependencyInjection to Volo.Abp.Autofac module. --- .../AutofacRegistration.cs | 140 +++++++++++++----- .../AutofacServiceProvider.cs | 122 --------------- .../AutofacServiceProviderFactory.cs | 77 ---------- .../AutofacServiceScope.cs | 67 --------- .../AutofacServiceScopeFactory.cs | 65 -------- .../Volo.Abp.Autofac/Volo.Abp.Autofac.csproj | 2 + 6 files changed, 108 insertions(+), 365 deletions(-) delete mode 100644 framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs delete mode 100644 framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProviderFactory.cs delete mode 100644 framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScope.cs delete mode 100644 framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScopeFactory.cs diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs b/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs index 024fc3a258..aeb0de9f2f 100644 --- a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs +++ b/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs @@ -1,6 +1,6 @@ // This software is part of the Autofac IoC container // Copyright © 2015 Autofac Contributors -// http://autofac.org +// https://autofac.org // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -24,9 +24,12 @@ // OTHER DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using Autofac.Builder; using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; using Volo.Abp.Modularity; namespace Autofac.Extensions.DependencyInjection @@ -45,16 +48,62 @@ namespace Autofac.Extensions.DependencyInjection /// The into which the registrations should be made. /// /// - /// The set of service descriptors to register in the container. + /// A container builder that can be used to create an . /// public static void Populate( - this ContainerBuilder builder, - IServiceCollection services) + this ContainerBuilder builder, + IServiceCollection services) { - builder.RegisterType().As(); - builder.RegisterType().As(); + Populate(builder, services, null); + } + + /// + /// Populates the Autofac container builder with the set of registered service descriptors + /// and makes and + /// available in the container. Using this overload is incompatible with the ASP.NET Core + /// support for . + /// + /// + /// The into which the registrations should be made. + /// + /// + /// A container builder that can be used to create an . + /// + /// + /// If provided and not then all registrations with lifetime are registered + /// using + /// with provided + /// instead of using . + /// + /// + /// + /// Specifying a addresses a specific case where you have + /// an application that uses Autofac but where you need to isolate a set of services in a child scope. For example, + /// if you have a large application that self-hosts ASP.NET Core items, you may want to isolate the ASP.NET + /// Core registrations in a child lifetime scope so they don't show up for the rest of the application. + /// This overload allows that. Note it is the developer's responsibility to execute this and create an + /// using the child lifetime scope. + /// + /// + public static void Populate( + this ContainerBuilder builder, + IServiceCollection services, + object lifetimeScopeTagForSingletons) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } - Register(builder, services); + builder.RegisterType().As().ExternallyOwned(); + var autofacServiceScopeFactory = typeof(AutofacServiceProvider).Assembly.GetType("Autofac.Extensions.DependencyInjection.AutofacServiceScopeFactory"); + if (autofacServiceScopeFactory == null) + { + throw new AbpException("Unable get type of Autofac.Extensions.DependencyInjection.AutofacServiceScopeFactory!"); + } + builder.RegisterType(autofacServiceScopeFactory).As(); + + Register(builder, services, lifetimeScopeTagForSingletons); } /// @@ -64,18 +113,33 @@ namespace Autofac.Extensions.DependencyInjection /// The object registration style. /// The registration being built. /// The lifecycle specified on the service registration. + /// + /// If not then all registrations with lifetime are registered + /// using + /// with provided + /// instead of using . + /// /// /// The , configured with the proper lifetime scope, /// and available for additional configuration. /// private static IRegistrationBuilder ConfigureLifecycle( - this IRegistrationBuilder registrationBuilder, - ServiceLifetime lifecycleKind) + this IRegistrationBuilder registrationBuilder, + ServiceLifetime lifecycleKind, + object lifetimeScopeTagForSingleton) { switch (lifecycleKind) { case ServiceLifetime.Singleton: - registrationBuilder.SingleInstance(); + if (lifetimeScopeTagForSingleton == null) + { + registrationBuilder.SingleInstance(); + } + else + { + registrationBuilder.InstancePerMatchingLifetimeScope(lifetimeScopeTagForSingleton); + } + break; case ServiceLifetime.Scoped: registrationBuilder.InstancePerLifetimeScope(); @@ -95,57 +159,65 @@ namespace Autofac.Extensions.DependencyInjection /// The into which the registrations should be made. /// /// - /// The set of service descriptors to register in the container. + /// A container builder that can be used to create an . + /// + /// + /// If not then all registrations with lifetime are registered + /// using + /// with provided + /// instead of using . /// + [SuppressMessage("CA2000", "CA2000", Justification = "Registrations created here are disposed when the built container is disposed.")] private static void Register( - ContainerBuilder builder, - IServiceCollection services) + ContainerBuilder builder, + IServiceCollection services, + object lifetimeScopeTagForSingletons) { var moduleContainer = services.GetSingletonInstance(); var registrationActionList = services.GetRegistrationActionList(); - foreach (var service in services) + foreach (var descriptor in services) { - if (service.ImplementationType != null) + if (descriptor.ImplementationType != null) { // Test if the an open generic type is being registered - var serviceTypeInfo = service.ServiceType.GetTypeInfo(); + var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo(); if (serviceTypeInfo.IsGenericTypeDefinition) { builder - .RegisterGeneric(service.ImplementationType) - .As(service.ServiceType) - .ConfigureLifecycle(service.Lifetime) + .RegisterGeneric(descriptor.ImplementationType) + .As(descriptor.ServiceType) + .ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons) .ConfigureAbpConventions(moduleContainer, registrationActionList); } else { builder - .RegisterType(service.ImplementationType) - .As(service.ServiceType) - .ConfigureLifecycle(service.Lifetime) + .RegisterType(descriptor.ImplementationType) + .As(descriptor.ServiceType) + .ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons) .ConfigureAbpConventions(moduleContainer, registrationActionList); } } - else if (service.ImplementationFactory != null) + else if (descriptor.ImplementationFactory != null) { - var registration = RegistrationBuilder.ForDelegate(service.ServiceType, (context, parameters) => - { - var serviceProvider = context.Resolve(); - return service.ImplementationFactory(serviceProvider); - }) - .ConfigureLifecycle(service.Lifetime) - .CreateRegistration(); - //TODO: ConfigureAbpConventions ? + var registration = RegistrationBuilder.ForDelegate(descriptor.ServiceType, (context, parameters) => + { + var serviceProvider = context.Resolve(); + return descriptor.ImplementationFactory(serviceProvider); + }) + .ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons) + .CreateRegistration(); + //TODO: ConfigureAbpConventions ? builder.RegisterComponent(registration); } else { builder - .RegisterInstance(service.ImplementationInstance) - .As(service.ServiceType) - .ConfigureLifecycle(service.Lifetime); + .RegisterInstance(descriptor.ImplementationInstance) + .As(descriptor.ServiceType) + .ConfigureLifecycle(descriptor.Lifetime, null); } } } diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs b/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs deleted file mode 100644 index 1c1a24ff66..0000000000 --- a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs +++ /dev/null @@ -1,122 +0,0 @@ -// This software is part of the Autofac IoC container -// Copyright © 2015 Autofac Contributors -// https://autofac.org -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Autofac.Extensions.DependencyInjection -{ - /// - /// Autofac implementation of the ASP.NET Core . - /// - /// - /// - public class AutofacServiceProvider : IServiceProvider, ISupportRequiredService, IDisposable - { - private readonly ILifetimeScope _lifetimeScope; - - private bool _disposed = false; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The lifetime scope from which services will be resolved. - /// - public AutofacServiceProvider(ILifetimeScope lifetimeScope) - { - this._lifetimeScope = lifetimeScope; - } - - /// - /// Gets service of type from the - /// and requires it be present. - /// - /// - /// An object that specifies the type of service object to get. - /// - /// - /// A service object of type . - /// - /// - /// Thrown if the isn't registered with the container. - /// - /// - /// Thrown if the object can't be resolved from the container. - /// - public object GetRequiredService(Type serviceType) - { - return this._lifetimeScope.Resolve(serviceType); - } - - /// - /// Gets the service object of the specified type. - /// - /// - /// An object that specifies the type of service object to get. - /// - /// - /// A service object of type ; or - /// if there is no service object of type . - /// - public object GetService(Type serviceType) - { - return this._lifetimeScope.ResolveOptional(serviceType); - } - - /// - /// Gets the underlying instance of . - /// - public ILifetimeScope LifetimeScope => _lifetimeScope; - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// - /// to release both managed and unmanaged resources; - /// to release only unmanaged resources. - /// - protected virtual void Dispose(bool disposing) - { - if (!this._disposed) - { - this._disposed = true; - if (disposing) - { - this._lifetimeScope.Dispose(); - } - } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProviderFactory.cs b/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProviderFactory.cs deleted file mode 100644 index 21a7ca331d..0000000000 --- a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProviderFactory.cs +++ /dev/null @@ -1,77 +0,0 @@ -// This software is part of the Autofac IoC container -// Copyright © 2017 Autofac Contributors -// http://autofac.org -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Autofac.Extensions.DependencyInjection -{ - /// - /// A factory for creating a and an . - /// - public class AutofacServiceProviderFactory : IServiceProviderFactory - { - private readonly Action _configurationAction; - - /// - /// Initializes a new instance of the class. - /// - /// Action on a that adds component registrations to the container. - public AutofacServiceProviderFactory(Action configurationAction = null) - { - _configurationAction = configurationAction ?? (builder => { }); - } - - /// - /// Creates a container builder from an . - /// - /// The collection of services - /// A container builder that can be used to create an . - public ContainerBuilder CreateBuilder(IServiceCollection services) - { - var builder = new ContainerBuilder(); - - builder.Populate(services); - - _configurationAction(builder); - - return builder; - } - - /// - /// Creates an from the container builder. - /// - /// The container builder - /// An - public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder) - { - if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder)); - - var container = containerBuilder.Build(); - - return new AutofacServiceProvider(container); - } - } -} diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScope.cs b/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScope.cs deleted file mode 100644 index 425c6769da..0000000000 --- a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScope.cs +++ /dev/null @@ -1,67 +0,0 @@ -// This software is part of the Autofac IoC container -// Copyright © 2015 Autofac Contributors -// http://autofac.org -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Autofac.Extensions.DependencyInjection -{ - /// - /// Autofac implementation of the ASP.NET Core . - /// - /// - internal class AutofacServiceScope : IServiceScope - { - private readonly ILifetimeScope _lifetimeScope; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The lifetime scope from which services should be resolved for this service scope. - /// - public AutofacServiceScope(ILifetimeScope lifetimeScope) - { - this._lifetimeScope = lifetimeScope; - this.ServiceProvider = this._lifetimeScope.Resolve(); - } - - /// - /// Gets an corresponding to this service scope. - /// - /// - /// An that can be used to resolve dependencies from the scope. - /// - public IServiceProvider ServiceProvider { get; } - - /// - /// Disposes of the lifetime scope and resolved disposable services. - /// - public void Dispose() - { - this._lifetimeScope.Dispose(); - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScopeFactory.cs b/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScopeFactory.cs deleted file mode 100644 index 31917fd079..0000000000 --- a/framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScopeFactory.cs +++ /dev/null @@ -1,65 +0,0 @@ -// This software is part of the Autofac IoC container -// Copyright © 2015 Autofac Contributors -// http://autofac.org -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -using System.Diagnostics.CodeAnalysis; -using Microsoft.Extensions.DependencyInjection; - -namespace Autofac.Extensions.DependencyInjection -{ - /// - /// Autofac implementation of the ASP.NET Core . - /// - /// - [SuppressMessage("Microsoft.ApiDesignGuidelines", "CA2213", Justification = "The creator of the root service lifetime scope is responsible for disposal.")] - internal class AutofacServiceScopeFactory : IServiceScopeFactory - { - private readonly ILifetimeScope _lifetimeScope; - - /// - /// Initializes a new instance of the class. - /// - /// The lifetime scope. - public AutofacServiceScopeFactory(ILifetimeScope lifetimeScope) - { - this._lifetimeScope = lifetimeScope; - } - - /// - /// Creates an which contains an - /// used to resolve dependencies within - /// the scope. - /// - /// - /// An controlling the lifetime of the scope. Once - /// this is disposed, any scoped services that have been resolved - /// from the - /// will also be disposed. - /// - public IServiceScope CreateScope() - { - return new AutofacServiceScope(this._lifetimeScope.BeginLifetimeScope()); - } - } -} \ 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 2032464676..465c645328 100644 --- a/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj +++ b/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj @@ -17,6 +17,8 @@ + + From cfecb1f8d9f718735ea2a3cad947840c312625cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 21 Dec 2020 16:31:55 +0300 Subject: [PATCH 02/83] Implemented creating dbcontext in async way. --- .../Repositories/IReadOnlyRepository.cs | 9 + .../Abp/Domain/Repositories/RepositoryBase.cs | 20 +++ .../EntityFrameworkCore/EfCoreRepository.cs | 113 ++++++++---- .../EntityFrameworkCore/IEfCoreRepository.cs | 10 +- .../EntityFrameworkCore/IDbContextProvider.cs | 8 +- .../UnitOfWorkDbContextProvider.cs | 104 ++++++++++- .../MemoryDb/MemoryDbRepository.cs | 6 + .../MongoDB/IMongoDbRepository.cs | 14 +- .../Repositories/MongoDB/MongoDbRepository.cs | 161 ++++++++++++------ .../Abp/MongoDB/IMongoDbContextProvider.cs | 13 +- .../UnitOfWorkMongoDbContextProvider.cs | 109 +++++++++++- .../RepositoryRegistration_Tests.cs | 6 + 12 files changed, 477 insertions(+), 96 deletions(-) diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IReadOnlyRepository.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IReadOnlyRepository.cs index 499a1e58be..80d1425044 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IReadOnlyRepository.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IReadOnlyRepository.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using System.Threading.Tasks; using Volo.Abp.Domain.Entities; using Volo.Abp.Linq; @@ -11,9 +12,17 @@ namespace Volo.Abp.Domain.Repositories { IAsyncQueryableExecuter AsyncExecuter { get; } + [Obsolete("Use WithDetailsAsync method.")] IQueryable WithDetails(); + [Obsolete("Use WithDetailsAsync method.")] IQueryable WithDetails(params Expression>[] propertySelectors); + + Task> WithDetailsAsync(); //TODO: CancellationToken + + Task> WithDetailsAsync(params Expression>[] propertySelectors); //TODO: CancellationToken + + Task> GetQueryableAsync(); //TODO: CancellationToken } public interface IReadOnlyRepository : IReadOnlyRepository, IReadOnlyBasicRepository diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs index fd66b293c9..4ee118fcfe 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryBase.cs @@ -24,34 +24,54 @@ namespace Volo.Abp.Domain.Repositories public IUnitOfWorkManager UnitOfWorkManager { get; set; } + [Obsolete("This method will be removed in future versions.")] public virtual Type ElementType => GetQueryable().ElementType; + [Obsolete("This method will be removed in future versions.")] public virtual Expression Expression => GetQueryable().Expression; + [Obsolete("This method will be removed in future versions.")] public virtual IQueryProvider Provider => GetQueryable().Provider; + [Obsolete("Use WithDetailsAsync method.")] public virtual IQueryable WithDetails() { return GetQueryable(); } + [Obsolete("Use WithDetailsAsync method.")] public virtual IQueryable WithDetails(params Expression>[] propertySelectors) { return GetQueryable(); } + public virtual Task> WithDetailsAsync() + { + return GetQueryableAsync(); + } + + public virtual Task> WithDetailsAsync(params Expression>[] propertySelectors) + { + return GetQueryableAsync(); + } + + [Obsolete("This method will be removed in future versions.")] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + [Obsolete("This method will be removed in future versions.")] public IEnumerator GetEnumerator() { return GetQueryable().GetEnumerator(); } + [Obsolete("Use GetQueryableAsync method.")] protected abstract IQueryable GetQueryable(); + public abstract Task> GetQueryableAsync(); + public abstract Task FindAsync( Expression> predicate, bool includeDetails = true, diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index 0d44fd1249..bee421dbe2 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -19,11 +19,34 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore where TDbContext : IEfCoreDbContext where TEntity : class, IEntity { - public virtual DbSet DbSet => DbContext.Set(); + [Obsolete("Use GetDbContextAsync() method.")] + protected virtual TDbContext DbContext => _dbContextProvider.GetDbContext(); + [Obsolete("Use GetDbContextAsync() method.")] DbContext IEfCoreRepository.DbContext => DbContext.As(); - protected virtual TDbContext DbContext => _dbContextProvider.GetDbContext(); + async Task IEfCoreRepository.GetDbContextAsync() + { + return await GetDbContextAsync() as DbContext; + } + + protected virtual Task GetDbContextAsync() + { + return _dbContextProvider.GetDbContextAsync(); + } + + [Obsolete("Use GetDbSetAsync() method.")] + public virtual DbSet DbSet => DbContext.Set(); + + Task> IEfCoreRepository.GetDbSetAsync() + { + return GetDbSetAsync(); + } + + protected async Task> GetDbSetAsync() + { + return (await GetDbContextAsync()).Set(); + } protected virtual AbpEntityOptions AbpEntityOptions => _entityOptionsLazy.Value; @@ -45,64 +68,72 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore ); } - public async override Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { CheckAndSetId(entity); - var savedEntity = DbSet.Add(entity).Entity; + var dbContext = await GetDbContextAsync(); + + var savedEntity = (await dbContext.Set().AddAsync(entity, GetCancellationToken(cancellationToken))).Entity; if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await dbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } return savedEntity; } - public async override Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { - DbContext.Attach(entity); + var dbContext = await GetDbContextAsync(); - var updatedEntity = DbContext.Update(entity).Entity; + dbContext.Attach(entity); + + var updatedEntity = dbContext.Update(entity).Entity; if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await dbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } return updatedEntity; } - public async override Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { - DbSet.Remove(entity); + var dbContext = await GetDbContextAsync(); + + dbContext.Set().Remove(entity); if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await dbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } } - public async override Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) + public override async Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { return includeDetails - ? await WithDetails().ToListAsync(GetCancellationToken(cancellationToken)) - : await DbSet.ToListAsync(GetCancellationToken(cancellationToken)); + ? await (await WithDetailsAsync()).ToListAsync(GetCancellationToken(cancellationToken)) + : await (await GetDbSetAsync()).ToListAsync(GetCancellationToken(cancellationToken)); } - public async override Task GetCountAsync(CancellationToken cancellationToken = default) + public override async Task GetCountAsync(CancellationToken cancellationToken = default) { - return await DbSet.LongCountAsync(GetCancellationToken(cancellationToken)); + return await (await GetDbSetAsync()).LongCountAsync(GetCancellationToken(cancellationToken)); } - public async override Task> GetPagedListAsync( + public override async Task> GetPagedListAsync( int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default) { - var queryable = includeDetails ? WithDetails() : DbSet; + var queryable = includeDetails + ? await WithDetailsAsync() + : await GetDbSetAsync(); return await queryable .OrderBy(sorting) @@ -110,39 +141,48 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore .ToListAsync(GetCancellationToken(cancellationToken)); } + [Obsolete("Use GetQueryableAsync method.")] protected override IQueryable GetQueryable() { return DbSet.AsQueryable(); } - public async override Task FindAsync( + public override async Task> GetQueryableAsync() + { + return (await GetDbSetAsync()).AsQueryable(); + } + + public override async Task FindAsync( Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { return includeDetails - ? await WithDetails() + ? await (await WithDetailsAsync()) .Where(predicate) .SingleOrDefaultAsync(GetCancellationToken(cancellationToken)) - : await DbSet + : await (await GetDbSetAsync()) .Where(predicate) .SingleOrDefaultAsync(GetCancellationToken(cancellationToken)); } - public async override Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { - var entities = await GetQueryable() + var dbContext = await GetDbContextAsync(); + var dbSet = dbContext.Set(); + + var entities = await dbSet .Where(predicate) .ToListAsync(GetCancellationToken(cancellationToken)); foreach (var entity in entities) { - DbSet.Remove(entity); + dbSet.Remove(entity); } if (autoSave) { - await DbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); + await dbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } } @@ -152,7 +192,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore CancellationToken cancellationToken = default) where TProperty : class { - await DbContext + await (await GetDbContextAsync()) .Entry(entity) .Collection(propertyExpression) .LoadAsync(GetCancellationToken(cancellationToken)); @@ -164,12 +204,13 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore CancellationToken cancellationToken = default) where TProperty : class { - await DbContext + await (await GetDbContextAsync()) .Entry(entity) .Reference(propertyExpression) .LoadAsync(GetCancellationToken(cancellationToken)); } + [Obsolete("Use WithDetailsAsync")] public override IQueryable WithDetails() { if (AbpEntityOptions.DefaultWithDetailsFunc == null) @@ -180,6 +221,17 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return AbpEntityOptions.DefaultWithDetailsFunc(GetQueryable()); } + public override async Task> WithDetailsAsync() + { + if (AbpEntityOptions.DefaultWithDetailsFunc == null) + { + return await base.WithDetailsAsync(); + } + + return AbpEntityOptions.DefaultWithDetailsFunc(await GetQueryableAsync()); + } + + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails(params Expression>[] propertySelectors) { var query = GetQueryable(); @@ -195,6 +247,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return query; } + [Obsolete("This method will be deleted in future versions.")] public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) { return DbSet.AsAsyncEnumerable().GetAsyncEnumerator(cancellationToken); @@ -251,8 +304,8 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore public virtual async Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { return includeDetails - ? await WithDetails().FirstOrDefaultAsync(e => e.Id.Equals(id), GetCancellationToken(cancellationToken)) - : await DbSet.FindAsync(new object[] {id}, GetCancellationToken(cancellationToken)); + ? await (await WithDetailsAsync()).FirstOrDefaultAsync(e => e.Id.Equals(id), GetCancellationToken(cancellationToken)) + : await (await GetDbSetAsync()).FindAsync(new object[] {id}, GetCancellationToken(cancellationToken)); } public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/IEfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/IEfCoreRepository.cs index 31a78f744d..f793dc04ed 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/IEfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/IEfCoreRepository.cs @@ -1,3 +1,5 @@ +using System; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Entities; @@ -6,9 +8,15 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore public interface IEfCoreRepository : IRepository where TEntity : class, IEntity { + [Obsolete("Use GetDbContextAsync() method.")] DbContext DbContext { get; } + [Obsolete("Use GetDbSetAsync() method.")] DbSet DbSet { get; } + + Task GetDbContextAsync(); + + Task> GetDbSetAsync(); } public interface IEfCoreRepository : IEfCoreRepository, IRepository @@ -16,4 +24,4 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore { } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs index c4655fddd0..17af400b97 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs @@ -1,8 +1,12 @@ +using System.Threading.Tasks; + namespace Volo.Abp.EntityFrameworkCore { - public interface IDbContextProvider + public interface IDbContextProvider where TDbContext : IEfCoreDbContext { TDbContext GetDbContext(); + + Task GetDbContextAsync(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs index 91ed2f8126..acd414af83 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs @@ -1,6 +1,6 @@ using System; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Data; @@ -47,6 +47,33 @@ namespace Volo.Abp.Uow.EntityFrameworkCore return ((EfCoreDatabaseApi)databaseApi).DbContext; } + public async Task GetDbContextAsync() + { + var unitOfWork = _unitOfWorkManager.Current; + if (unitOfWork == null) + { + throw new AbpException("A DbContext can only be created inside a unit of work!"); + } + + var connectionStringName = ConnectionStringNameAttribute.GetConnStringName(); + var connectionString = _connectionStringResolver.Resolve(connectionStringName); + + var dbContextKey = $"{typeof(TDbContext).FullName}_{connectionString}"; + + var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey); + + if (databaseApi == null) + { + databaseApi = new EfCoreDatabaseApi( + await CreateDbContextAsync(unitOfWork, connectionStringName, connectionString) + ); + + unitOfWork.AddDatabaseApi(dbContextKey, databaseApi); + } + + return ((EfCoreDatabaseApi)databaseApi).DbContext; + } + private TDbContext CreateDbContext(IUnitOfWork unitOfWork, string connectionStringName, string connectionString) { var creationContext = new DbContextCreationContext(connectionStringName, connectionString); @@ -67,6 +94,26 @@ namespace Volo.Abp.Uow.EntityFrameworkCore } } + private async Task CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName, string connectionString) + { + var creationContext = new DbContextCreationContext(connectionStringName, connectionString); + using (DbContextCreationContext.Use(creationContext)) + { + var dbContext = await CreateDbContextAsync(unitOfWork); + + if (dbContext is IAbpEfCoreDbContext abpEfCoreDbContext) + { + abpEfCoreDbContext.Initialize( + new AbpEfCoreDbContextInitializationContext( + unitOfWork + ) + ); + } + + return dbContext; + } + } + private TDbContext CreateDbContext(IUnitOfWork unitOfWork) { return unitOfWork.Options.IsTransactional @@ -74,7 +121,14 @@ namespace Volo.Abp.Uow.EntityFrameworkCore : unitOfWork.ServiceProvider.GetRequiredService(); } - public TDbContext CreateDbContextWithTransaction(IUnitOfWork unitOfWork) + private async Task CreateDbContextAsync(IUnitOfWork unitOfWork) + { + return unitOfWork.Options.IsTransactional + ? await CreateDbContextWithTransactionAsync(unitOfWork) + : unitOfWork.ServiceProvider.GetRequiredService(); + } + + private TDbContext CreateDbContextWithTransaction(IUnitOfWork unitOfWork) { var transactionApiKey = $"EntityFrameworkCore_{DbContextCreationContext.Current.ConnectionString}"; var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as EfCoreTransactionApi; @@ -117,5 +171,49 @@ namespace Volo.Abp.Uow.EntityFrameworkCore return dbContext; } } + + private async Task CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork) + { + var transactionApiKey = $"EntityFrameworkCore_{DbContextCreationContext.Current.ConnectionString}"; + var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as EfCoreTransactionApi; + + if (activeTransaction == null) + { + var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); + + var dbtransaction = unitOfWork.Options.IsolationLevel.HasValue + ? await dbContext.Database.BeginTransactionAsync(unitOfWork.Options.IsolationLevel.Value) + : await dbContext.Database.BeginTransactionAsync(); + + unitOfWork.AddTransactionApi( + transactionApiKey, + new EfCoreTransactionApi( + dbtransaction, + dbContext + ) + ); + + return dbContext; + } + else + { + DbContextCreationContext.Current.ExistingConnection = activeTransaction.DbContextTransaction.GetDbTransaction().Connection; + + var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); + + if (dbContext.As().HasRelationalTransactionManager()) + { + await dbContext.Database.UseTransactionAsync(activeTransaction.DbContextTransaction.GetDbTransaction()); + } + else + { + await dbContext.Database.BeginTransactionAsync(); //TODO: Why not using the new created transaction? + } + + activeTransaction.AttendedDbContexts.Add(dbContext); + + return dbContext; + } + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index bb77149a29..17b3f09adc 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -46,11 +46,17 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb EntityChangeEventHelper = NullEntityChangeEventHelper.Instance; } + [Obsolete("This method will be removed in future versions.")] protected override IQueryable GetQueryable() { return ApplyDataFilters(Collection.AsQueryable()); } + public override Task> GetQueryableAsync() + { + return Task.FromResult(ApplyDataFilters(Collection.AsQueryable())); + } + protected virtual async Task TriggerDomainEventsAsync(object entity) { var generatesDomainEventsEntity = entity as IGeneratesDomainEvents; diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs index 50155c6df5..960222679f 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/IMongoDbRepository.cs @@ -1,4 +1,7 @@ -using MongoDB.Driver; +using System; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver; using MongoDB.Driver.Linq; using Volo.Abp.Domain.Entities; @@ -7,11 +10,20 @@ namespace Volo.Abp.Domain.Repositories.MongoDB public interface IMongoDbRepository : IRepository where TEntity : class, IEntity { + [Obsolete("Use GetDatabaseAsync method.")] IMongoDatabase Database { get; } + Task GetDatabaseAsync(CancellationToken cancellationToken = default); + + [Obsolete("Use GetCollectionAsync method.")] IMongoCollection Collection { get; } + Task> GetCollectionAsync(CancellationToken cancellationToken = default); + + [Obsolete("Use GetMongoQueryableAsync method.")] IMongoQueryable GetMongoQueryable(); + + Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default); } public interface IMongoDbRepository : IMongoDbRepository, IRepository diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 6af98da56b..5f1025f77d 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -25,13 +25,37 @@ namespace Volo.Abp.Domain.Repositories.MongoDB where TMongoDbContext : IAbpMongoDbContext where TEntity : class, IEntity { + [Obsolete("Use GetCollectionAsync method.")] public virtual IMongoCollection Collection => DbContext.Collection(); + public async Task> GetCollectionAsync(CancellationToken cancellationToken = default) + { + return (await GetDbContextAsync(GetCancellationToken(cancellationToken))).Collection(); + } + + [Obsolete("Use GetDatabaseAsync method.")] public virtual IMongoDatabase Database => DbContext.Database; - public virtual IClientSessionHandle SessionHandle => DbContext.SessionHandle; + public async Task GetDatabaseAsync(CancellationToken cancellationToken = default) + { + return (await GetDbContextAsync(GetCancellationToken(cancellationToken))).Database; + } + + [Obsolete("Use GetSessionHandleAsync method.")] + protected virtual IClientSessionHandle SessionHandle => DbContext.SessionHandle; + + protected async Task GetSessionHandleAsync(CancellationToken cancellationToken = default) + { + return (await GetDbContextAsync(GetCancellationToken(cancellationToken))).SessionHandle; + } + + [Obsolete("Use GetDbContextAsync method.")] + protected virtual TMongoDbContext DbContext => DbContextProvider.GetDbContext(); - public virtual TMongoDbContext DbContext => DbContextProvider.GetDbContext(); + protected Task GetDbContextAsync(CancellationToken cancellationToken = default) + { + return DbContextProvider.GetDbContextAsync(GetCancellationToken(cancellationToken)); + } protected IMongoDbContextProvider DbContextProvider { get; } @@ -55,24 +79,27 @@ namespace Volo.Abp.Domain.Repositories.MongoDB GuidGenerator = SimpleGuidGenerator.Instance; } - public async override Task InsertAsync( + public override async Task InsertAsync( TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { await ApplyAbpConceptsForAddedEntityAsync(entity); - if (SessionHandle != null) + var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken)); + var collection = dbContext.Collection(); + + if (dbContext.SessionHandle != null) { - await Collection.InsertOneAsync( - SessionHandle, + await collection.InsertOneAsync( + dbContext.SessionHandle, entity, cancellationToken: GetCancellationToken(cancellationToken) ); } else { - await Collection.InsertOneAsync( + await collection.InsertOneAsync( entity, cancellationToken: GetCancellationToken(cancellationToken) ); @@ -81,7 +108,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB return entity; } - public async override Task UpdateAsync( + public override async Task UpdateAsync( TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) @@ -103,20 +130,21 @@ namespace Volo.Abp.Domain.Repositories.MongoDB var oldConcurrencyStamp = SetNewConcurrencyStamp(entity); ReplaceOneResult result; - if (SessionHandle != null) + var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken)); + var collection = dbContext.Collection(); + + if (dbContext.SessionHandle != null) { - result = await Collection.ReplaceOneAsync( - SessionHandle, + result = await collection.ReplaceOneAsync( + dbContext.SessionHandle, CreateEntityFilter(entity, true, oldConcurrencyStamp), entity, cancellationToken: GetCancellationToken(cancellationToken) ); - - } else { - result = await Collection.ReplaceOneAsync( + result = await collection.ReplaceOneAsync( CreateEntityFilter(entity, true, oldConcurrencyStamp), entity, cancellationToken: GetCancellationToken(cancellationToken) @@ -131,7 +159,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB return entity; } - public async override Task DeleteAsync( + public override async Task DeleteAsync( TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) @@ -139,15 +167,18 @@ namespace Volo.Abp.Domain.Repositories.MongoDB await ApplyAbpConceptsForDeletedEntityAsync(entity); var oldConcurrencyStamp = SetNewConcurrencyStamp(entity); + var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken)); + var collection = dbContext.Collection(); + if (entity is ISoftDelete softDeleteEntity && !IsHardDeleted(entity)) { softDeleteEntity.IsDeleted = true; ReplaceOneResult result; - if (SessionHandle != null) + if (dbContext.SessionHandle != null) { - result = await Collection.ReplaceOneAsync( - SessionHandle, + result = await collection.ReplaceOneAsync( + dbContext.SessionHandle, CreateEntityFilter(entity, true, oldConcurrencyStamp), entity, cancellationToken: GetCancellationToken(cancellationToken) @@ -155,7 +186,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB } else { - result = await Collection.ReplaceOneAsync( + result = await collection.ReplaceOneAsync( CreateEntityFilter(entity, true, oldConcurrencyStamp), entity, cancellationToken: GetCancellationToken(cancellationToken) @@ -171,17 +202,17 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { DeleteResult result; - if (SessionHandle != null) + if (dbContext.SessionHandle != null) { - result = await Collection.DeleteOneAsync( - SessionHandle, + result = await collection.DeleteOneAsync( + dbContext.SessionHandle, CreateEntityFilter(entity, true, oldConcurrencyStamp), cancellationToken: GetCancellationToken(cancellationToken) ); } else { - result = await Collection.DeleteOneAsync( + result = await collection.DeleteOneAsync( CreateEntityFilter(entity, true, oldConcurrencyStamp), GetCancellationToken(cancellationToken) ); @@ -194,38 +225,44 @@ namespace Volo.Abp.Domain.Repositories.MongoDB } } - public async override Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) + public override async Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().ToListAsync(GetCancellationToken(cancellationToken)); + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)).ToListAsync(cancellationToken); } - public async override Task GetCountAsync(CancellationToken cancellationToken = default) + public override async Task GetCountAsync(CancellationToken cancellationToken = default) { - return await GetMongoQueryable().LongCountAsync(GetCancellationToken(cancellationToken)); + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)).LongCountAsync(cancellationToken); } - public async override Task> GetPagedListAsync( + public override async Task> GetPagedListAsync( int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + + return await (await GetMongoQueryableAsync(cancellationToken)) .OrderBy(sorting) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(cancellationToken); } - public async override Task DeleteAsync( + public override async Task DeleteAsync( Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { - var entities = await GetMongoQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + + var entities = await (await GetMongoQueryableAsync(cancellationToken)) .Where(predicate) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(cancellationToken); foreach (var entity in entities) { @@ -233,25 +270,45 @@ namespace Volo.Abp.Domain.Repositories.MongoDB } } + [Obsolete("Use GetQueryableAsync method.")] protected override IQueryable GetQueryable() { return GetMongoQueryable(); } - public async override Task FindAsync( + public override async Task> GetQueryableAsync() + { + return await GetMongoQueryableAsync(); + } + + public override async Task FindAsync( Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(predicate) .SingleOrDefaultAsync(GetCancellationToken(cancellationToken)); } + [Obsolete("Use GetMongoQueryableAsync method.")] public virtual IMongoQueryable GetMongoQueryable() { return ApplyDataFilters(SessionHandle != null ? Collection.AsQueryable(SessionHandle) : Collection.AsQueryable()); } + + public async Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(cancellationToken); + var collection = dbContext.Collection(); + + return ApplyDataFilters( + dbContext.SessionHandle != null + ? collection.AsQueryable(dbContext.SessionHandle) + : collection.AsQueryable() + ); + } + protected virtual bool IsHardDeleted(TEntity entity) { var hardDeletedEntities = UnitOfWorkManager?.Current?.Items.GetOrDefault(UnitOfWorkItemNames.HardDeletedEntities) as HashSet; @@ -393,30 +450,19 @@ namespace Volo.Abp.Domain.Repositories.MongoDB throw new AbpDbConcurrencyException("Database operation expected to affect 1 row but actually affected 0 row. Data may have been modified or deleted since entities were loaded. This exception has been thrown on optimistic concurrency check."); } - /// - /// IMongoQueryable - /// - /// + [Obsolete("This method will be removed in future versions.")] public QueryableExecutionModel GetExecutionModel() { return GetMongoQueryable().GetExecutionModel(); } - /// - /// IMongoQueryable - /// - /// - /// + [Obsolete("This method will be removed in future versions.")] public IAsyncCursor ToCursor(CancellationToken cancellationToken = new CancellationToken()) { return GetMongoQueryable().ToCursor(cancellationToken); } - /// - /// IMongoQueryable - /// - /// - /// + [Obsolete("This method will be removed in future versions.")] public Task> ToCursorAsync(CancellationToken cancellationToken = new CancellationToken()) { return GetMongoQueryable().ToCursorAsync(cancellationToken); @@ -457,16 +503,21 @@ namespace Volo.Abp.Domain.Repositories.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - if (SessionHandle != null) + cancellationToken = GetCancellationToken(cancellationToken); + + var dbContext = await GetDbContextAsync(cancellationToken); + var collection = dbContext.Collection(); + + if (dbContext.SessionHandle != null) { - return await Collection - .Find(SessionHandle, RepositoryFilterer.CreateEntityFilter(id, true)) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + return await collection + .Find(dbContext.SessionHandle, RepositoryFilterer.CreateEntityFilter(id, true)) + .FirstOrDefaultAsync(cancellationToken); } - return await Collection + return await collection .Find(RepositoryFilterer.CreateEntityFilter(id, true)) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(cancellationToken); } public virtual Task DeleteAsync( diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoDbContextProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoDbContextProvider.cs index 9f89054dcc..959cb39df1 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoDbContextProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/IMongoDbContextProvider.cs @@ -1,8 +1,15 @@ -namespace Volo.Abp.MongoDB +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Volo.Abp.MongoDB { - public interface IMongoDbContextProvider + public interface IMongoDbContextProvider where TMongoDbContext : IAbpMongoDbContext { + [Obsolete("Use CreateDbContextAsync")] TMongoDbContext GetDbContext(); + + Task GetDbContextAsync(CancellationToken cancellationToken = default); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs index d3d8a419fb..8a9ecd5de6 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs @@ -1,4 +1,6 @@ using System; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson; using MongoDB.Driver; @@ -21,6 +23,7 @@ namespace Volo.Abp.Uow.MongoDB _connectionStringResolver = connectionStringResolver; } + [Obsolete("Use CreateDbContextAsync")] public TMongoDbContext GetDbContext() { var unitOfWork = _unitOfWorkManager.Current; @@ -48,6 +51,46 @@ namespace Volo.Abp.Uow.MongoDB return ((MongoDbDatabaseApi) databaseApi).DbContext; } + public async Task GetDbContextAsync(CancellationToken cancellationToken = default) + { + var unitOfWork = _unitOfWorkManager.Current; + if (unitOfWork == null) + { + throw new AbpException( + $"A {nameof(IMongoDatabase)} instance can only be created inside a unit of work!"); + } + + var connectionString = _connectionStringResolver.Resolve(); + var dbContextKey = $"{typeof(TMongoDbContext).FullName}_{connectionString}"; + + var mongoUrl = new MongoUrl(connectionString); + var databaseName = mongoUrl.DatabaseName; + if (databaseName.IsNullOrWhiteSpace()) + { + databaseName = ConnectionStringNameAttribute.GetConnStringName(); + } + + //TODO: Create only single MongoDbClient per connection string in an application (extract MongoClientCache for example). + var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey); + if (databaseApi == null) + { + databaseApi = new MongoDbDatabaseApi( + await CreateDbContextAsync( + unitOfWork, + mongoUrl, + databaseName, + cancellationToken + ) + ); + + unitOfWork.AddDatabaseApi(dbContextKey, databaseApi); + } + + return ((MongoDbDatabaseApi) databaseApi).DbContext; + } + + [Obsolete("Use CreateDbContextAsync")] + private TMongoDbContext CreateDbContext(IUnitOfWork unitOfWork, MongoUrl mongoUrl, string databaseName) { var client = new MongoClient(mongoUrl); @@ -64,7 +107,34 @@ namespace Volo.Abp.Uow.MongoDB return dbContext; } - public TMongoDbContext CreateDbContextWithTransaction( + private async Task CreateDbContextAsync( + IUnitOfWork unitOfWork, + MongoUrl mongoUrl, + string databaseName, + CancellationToken cancellationToken = default) + { + var client = new MongoClient(mongoUrl); + var database = client.GetDatabase(databaseName); + + if (unitOfWork.Options.IsTransactional) + { + return await CreateDbContextWithTransactionAsync( + unitOfWork, + mongoUrl, + client, + database, + cancellationToken + ); + } + + var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); + dbContext.ToAbpMongoDbContext().InitializeDatabase(database, client, null); + + return dbContext; + } + + [Obsolete("Use CreateDbContextWithTransactionAsync")] + private TMongoDbContext CreateDbContextWithTransaction( IUnitOfWork unitOfWork, MongoUrl url, MongoClient client, @@ -99,5 +169,42 @@ namespace Volo.Abp.Uow.MongoDB return dbContext; } + + private async Task CreateDbContextWithTransactionAsync( + IUnitOfWork unitOfWork, + MongoUrl url, + MongoClient client, + IMongoDatabase database, + CancellationToken cancellationToken = default) + { + var transactionApiKey = $"MongoDb_{url}"; + var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as MongoDbTransactionApi; + var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); + + if (activeTransaction?.SessionHandle == null) + { + var session = await client.StartSessionAsync(cancellationToken: cancellationToken); + + if (unitOfWork.Options.Timeout.HasValue) + { + session.AdvanceOperationTime(new BsonTimestamp(unitOfWork.Options.Timeout.Value)); + } + + session.StartTransaction(); + + unitOfWork.AddTransactionApi( + transactionApiKey, + new MongoDbTransactionApi(session) + ); + + dbContext.ToAbpMongoDbContext().InitializeDatabase(database, client, session); + } + else + { + dbContext.ToAbpMongoDbContext().InitializeDatabase(database, client, activeTransaction.SessionHandle); + } + + return dbContext; + } } } diff --git a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs index 57b8054784..3acd59a2b6 100644 --- a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs +++ b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs @@ -241,11 +241,17 @@ namespace Volo.Abp.Domain.Repositories where TEntity : class, IEntity { + [Obsolete("Use GetQueryableAsync method.")] protected override IQueryable GetQueryable() { throw new NotImplementedException(); } + public override Task> GetQueryableAsync() + { + throw new NotImplementedException(); + } + public override Task FindAsync(Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { throw new NotImplementedException(); From 420dfbe8b4affa728dace63533a5a9f053fb5170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 21 Dec 2020 17:01:31 +0300 Subject: [PATCH 03/83] Identity module EF core async fix. --- .../EFCoreIdentitySecurityLogRepository.cs | 29 +++--- .../EfCoreIdentityClaimTypeRepository.cs | 8 +- .../EfCoreIdentityLinkUserRepository.cs | 6 +- .../EfCoreIdentityRoleRepository.cs | 19 ++-- .../EfCoreIdentityUserRepository.cs | 90 ++++++++++++------- .../EfCoreOrganizationUnitRepository.cs | 66 +++++++++----- .../MongoOrganizationUnitRepository.cs | 62 +++++++------ 7 files changed, 177 insertions(+), 103 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs index ddccb3187f..91915cd9b8 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs @@ -34,7 +34,9 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = GetListQuery( + cancellationToken = GetCancellationToken(cancellationToken); + + var query = await GetListQueryAsync( startTime, endTime, applicationName, @@ -43,12 +45,13 @@ namespace Volo.Abp.Identity.EntityFrameworkCore userId, userName, clientId, - correlationId + correlationId, + cancellationToken ); return await query.OrderBy(sorting ?? nameof(IdentitySecurityLog.CreationTime) + " desc") .PageBy(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(cancellationToken); } public async Task GetCountAsync( @@ -63,7 +66,9 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string correlationId = null, CancellationToken cancellationToken = default) { - var query = GetListQuery( + cancellationToken = GetCancellationToken(cancellationToken); + + var query = await GetListQueryAsync( startTime, endTime, applicationName, @@ -72,18 +77,21 @@ namespace Volo.Abp.Identity.EntityFrameworkCore userId, userName, clientId, - correlationId + correlationId, + cancellationToken ); - return await query.LongCountAsync(GetCancellationToken(cancellationToken)); + return await query.LongCountAsync(cancellationToken); } public async Task GetByUserIdAsync(Guid id, Guid userId, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet.OrderBy(x => x.Id).FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, GetCancellationToken(cancellationToken)); + return await (await GetDbSetAsync()) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, GetCancellationToken(cancellationToken)); } - protected virtual IQueryable GetListQuery( + protected virtual async Task> GetListQueryAsync( DateTime? startTime = null, DateTime? endTime = null, string applicationName = null, @@ -92,9 +100,10 @@ namespace Volo.Abp.Identity.EntityFrameworkCore Guid? userId = null, string userName = null, string clientId = null, - string correlationId = null) + string correlationId = null, + CancellationToken cancellationToken = default) { - return DbSet.AsNoTracking() + return (await GetDbSetAsync()).AsNoTracking() .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime.Value) .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime < endTime.Value.AddDays(1).Date) .WhereIf(!applicationName.IsNullOrWhiteSpace(), securityLog => securityLog.ApplicationName == applicationName) diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityClaimTypeRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityClaimTypeRepository.cs index 0d0ff499c1..4cbdfb5725 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityClaimTypeRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityClaimTypeRepository.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore Guid? ignoredId = null, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .WhereIf(ignoredId != null, ct => ct.Id != ignoredId) .CountAsync(ct => ct.Name == name, GetCancellationToken(cancellationToken)) > 0; } @@ -34,7 +34,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string filter, CancellationToken cancellationToken = default) { - var identityClaimTypes = await DbSet + var identityClaimTypes = await (await GetDbSetAsync()) .WhereIf( !filter.IsNullOrWhiteSpace(), u => @@ -51,7 +51,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string filter = null, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .WhereIf( !filter.IsNullOrWhiteSpace(), u => @@ -59,4 +59,4 @@ namespace Volo.Abp.Identity.EntityFrameworkCore ).LongCountAsync(GetCancellationToken(cancellationToken)); } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs index 39b62c8f46..6920d1081e 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; @@ -20,7 +19,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore public async Task FindAsync(IdentityLinkUserInfo sourceLinkUserInfo, IdentityLinkUserInfo targetLinkUserInfo, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .OrderBy(x => x.Id).FirstOrDefaultAsync(x => x.SourceUserId == sourceLinkUserInfo.UserId && x.SourceTenantId == sourceLinkUserInfo.TenantId && x.TargetUserId == targetLinkUserInfo.UserId && x.TargetTenantId == targetLinkUserInfo.TenantId || @@ -31,7 +30,8 @@ namespace Volo.Abp.Identity.EntityFrameworkCore public async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default) { - return await DbSet.Where(x => + return await (await GetDbSetAsync()) + .Where(x => x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs index bb17d863aa..b1389afd6a 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .OrderBy(x => x.Id) .FirstOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, GetCancellationToken(cancellationToken)); @@ -36,7 +36,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || @@ -50,7 +50,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore IEnumerable ids, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(t => ids.Contains(t.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -58,23 +58,32 @@ namespace Volo.Abp.Identity.EntityFrameworkCore public virtual async Task> GetDefaultOnesAsync( bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet.IncludeDetails(includeDetails).Where(r => r.IsDefault).ToListAsync(GetCancellationToken(cancellationToken)); + return await (await GetDbSetAsync()) + .IncludeDetails(includeDetails) + .Where(r => r.IsDefault) + .ToListAsync(GetCancellationToken(cancellationToken)); } public async Task GetCountAsync( string filter = null, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.NormalizedName.Contains(filter)) .LongCountAsync(GetCancellationToken(cancellationToken)); } + [Obsolete("Use WithDetailsAsync")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index f5d8fd2bb5..853e980f01 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -6,7 +6,6 @@ using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Internal; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -24,7 +23,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .OrderBy(x => x.Id) .FirstOrDefaultAsync( @@ -37,20 +36,21 @@ namespace Volo.Abp.Identity.EntityFrameworkCore Guid id, CancellationToken cancellationToken = default) { - var query = from userRole in DbContext.Set() - join role in DbContext.Roles on userRole.RoleId equals role.Id + var dbContext = await GetDbContextAsync(); + var query = from userRole in dbContext.Set() + join role in dbContext.Roles on userRole.RoleId equals role.Id where userRole.UserId == id select role.Name; - var organizationUnitIds = DbContext.Set().Where(q => q.UserId == id).Select(q => q.OrganizationUnitId).ToArray(); + var organizationUnitIds = dbContext.Set().Where(q => q.UserId == id).Select(q => q.OrganizationUnitId).ToArray(); var organizationRoleIds = await ( - from ouRole in DbContext.Set() - join ou in DbContext.Set() on ouRole.OrganizationUnitId equals ou.Id + from ouRole in dbContext.Set() + join ou in dbContext.Set() on ouRole.OrganizationUnitId equals ou.Id where organizationUnitIds.Contains(ouRole.OrganizationUnitId) select ouRole.RoleId ).ToListAsync(GetCancellationToken(cancellationToken)); - var orgUnitRoleNameQuery = DbContext.Roles.Where(r => organizationRoleIds.Contains(r.Id)).Select(n => n.Name); + var orgUnitRoleNameQuery = dbContext.Roles.Where(r => organizationRoleIds.Contains(r.Id)).Select(n => n.Name); var resultQuery = query.Union(orgUnitRoleNameQuery); return await resultQuery.ToListAsync(GetCancellationToken(cancellationToken)); } @@ -59,10 +59,11 @@ namespace Volo.Abp.Identity.EntityFrameworkCore Guid id, CancellationToken cancellationToken = default) { - var query = from userOu in DbContext.Set() - join roleOu in DbContext.Set() on userOu.OrganizationUnitId equals roleOu.OrganizationUnitId - join ou in DbContext.Set() on roleOu.OrganizationUnitId equals ou.Id - join userOuRoles in DbContext.Roles on roleOu.RoleId equals userOuRoles.Id + var dbContext = await GetDbContextAsync(); + var query = from userOu in dbContext.Set() + join roleOu in dbContext.Set() on userOu.OrganizationUnitId equals roleOu.OrganizationUnitId + join ou in dbContext.Set() on roleOu.OrganizationUnitId equals ou.Id + join userOuRoles in dbContext.Roles on roleOu.RoleId equals userOuRoles.Id where userOu.UserId == id select userOuRoles.Name; @@ -77,7 +78,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .Where(u => u.Logins.Any(login => login.LoginProvider == loginProvider && login.ProviderKey == providerKey)) .OrderBy(x=>x.Id) @@ -89,7 +90,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .OrderBy(x => x.Id) .FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, GetCancellationToken(cancellationToken)); @@ -100,7 +101,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .Where(u => u.Claims.Any(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value)) .ToListAsync(GetCancellationToken(cancellationToken)); @@ -111,7 +112,9 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var role = await DbContext.Roles + var dbContext = await GetDbContextAsync(); + + var role = await dbContext.Roles .Where(x => x.NormalizedName == normalizedRoleName) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -121,7 +124,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return new List(); } - return await DbSet + return await dbContext.Users .IncludeDetails(includeDetails) .Where(u => u.Roles.Any(r => r.RoleId == role.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); @@ -135,7 +138,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .WhereIf( !filter.IsNullOrWhiteSpace(), @@ -156,24 +159,26 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = from userRole in DbContext.Set() - join role in DbContext.Roles.IncludeDetails(includeDetails) on userRole.RoleId equals role.Id + var dbContext = await GetDbContextAsync(); + + var query = from userRole in dbContext.Set() + join role in dbContext.Roles.IncludeDetails(includeDetails) on userRole.RoleId equals role.Id where userRole.UserId == id select role; //TODO: Needs improvement - var userOrganizationsQuery = from userOrg in DbContext.Set() - join ou in DbContext.OrganizationUnits.IncludeDetails(includeDetails) on userOrg.OrganizationUnitId equals ou.Id + var userOrganizationsQuery = from userOrg in dbContext.Set() + join ou in dbContext.OrganizationUnits.IncludeDetails(includeDetails) on userOrg.OrganizationUnitId equals ou.Id where userOrg.UserId == id select ou; - var orgUserRoleQuery = DbContext.Set() + var orgUserRoleQuery = dbContext.Set() .Where(q => userOrganizationsQuery .Select(t => t.Id) .Contains(q.OrganizationUnitId)) .Select(t => t.RoleId); - var orgRoles = DbContext.Roles.Where(q => orgUserRoleQuery.Contains(q.Id)); + var orgRoles = dbContext.Roles.Where(q => orgUserRoleQuery.Contains(q.Id)); var resultQuery = query.Union(orgRoles); return await resultQuery.ToListAsync(GetCancellationToken(cancellationToken)); @@ -200,9 +205,11 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = from userOU in DbContext.Set() - join ou in DbContext.OrganizationUnits.IncludeDetails(includeDetails) on userOU.OrganizationUnitId equals ou.Id - where userOU.UserId == id + var dbContext = await GetDbContextAsync(); + + var query = from userOu in dbContext.Set() + join ou in dbContext.OrganizationUnits.IncludeDetails(includeDetails) on userOu.OrganizationUnitId equals ou.Id + where userOu.UserId == id select ou; return await query.ToListAsync(GetCancellationToken(cancellationToken)); @@ -213,10 +220,13 @@ namespace Volo.Abp.Identity.EntityFrameworkCore CancellationToken cancellationToken = default ) { - var query = from userOu in DbContext.Set() - join user in DbSet on userOu.UserId equals user.Id + var dbContext = await GetDbContextAsync(); + + var query = from userOu in dbContext.Set() + join user in dbContext.Users on userOu.UserId equals user.Id where userOu.OrganizationUnitId == organizationUnitId select user; + return await query.ToListAsync(GetCancellationToken(cancellationToken)); } @@ -225,10 +235,13 @@ namespace Volo.Abp.Identity.EntityFrameworkCore CancellationToken cancellationToken = default ) { - var query = from userOu in DbContext.Set() - join user in DbSet on userOu.UserId equals user.Id + var dbContext = await GetDbContextAsync(); + + var query = from userOu in dbContext.Set() + join user in dbContext.Users on userOu.UserId equals user.Id where organizationUnitIds.Contains(userOu.OrganizationUnitId) select user; + return await query.ToListAsync(GetCancellationToken(cancellationToken)); } @@ -237,17 +250,26 @@ namespace Volo.Abp.Identity.EntityFrameworkCore CancellationToken cancellationToken = default ) { - var query = from userOu in DbContext.Set() - join user in DbSet on userOu.UserId equals user.Id - join ou in DbContext.Set() on userOu.OrganizationUnitId equals ou.Id + var dbContext = await GetDbContextAsync(); + + var query = from userOu in dbContext.Set() + join user in dbContext.Users on userOu.UserId equals user.Id + join ou in dbContext.Set() on userOu.OrganizationUnitId equals ou.Id where ou.Code.StartsWith(code) select user; + return await query.ToListAsync(GetCancellationToken(cancellationToken)); } + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs index d63d7a2228..c3a8975fec 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq.Dynamic.Core; using System.Linq; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -25,7 +26,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .Where(x => x.ParentId == parentId) .ToListAsync(GetCancellationToken(cancellationToken)); @@ -37,7 +38,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .Where(ou => ou.Code.StartsWith(code) && ou.Id != parentId.Value) .ToListAsync(GetCancellationToken(cancellationToken)); @@ -50,7 +51,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .OrderBy(sorting ?? nameof(OrganizationUnit.DisplayName)) .PageBy(skipCount, maxResultCount) @@ -62,7 +63,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .Where(t => ids.Contains(t.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); @@ -73,7 +74,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .OrderBy(x => x.Id) .FirstOrDefaultAsync( @@ -90,10 +91,13 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = from organizationRole in DbContext.Set() - join role in DbContext.Roles.IncludeDetails(includeDetails) on organizationRole.RoleId equals role.Id + var dbContext = await GetDbContextAsync(); + + var query = from organizationRole in dbContext.Set() + join role in dbContext.Roles.IncludeDetails(includeDetails) on organizationRole.RoleId equals role.Id where organizationRole.OrganizationUnitId == organizationUnit.Id select role; + query = query .OrderBy(sorting ?? nameof(IdentityRole.Name)) .PageBy(skipCount, maxResultCount); @@ -105,8 +109,10 @@ namespace Volo.Abp.Identity.EntityFrameworkCore OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) { - var query = from organizationRole in DbContext.Set() - join role in DbContext.Roles on organizationRole.RoleId equals role.Id + var dbContext = await GetDbContextAsync(); + + var query = from organizationRole in dbContext.Set() + join role in dbContext.Roles on organizationRole.RoleId equals role.Id where organizationRole.OrganizationUnitId == organizationUnit.Id select role; @@ -123,8 +129,9 @@ namespace Volo.Abp.Identity.EntityFrameworkCore CancellationToken cancellationToken = default) { var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToList(); + var dbContext = await GetDbContextAsync(); - return await DbContext.Roles + return await dbContext.Roles .Where(r => !roleIds.Contains(r.Id)) .IncludeDetails(includeDetails) .WhereIf(!filter.IsNullOrWhiteSpace(), r => r.Name.Contains(filter)) @@ -139,8 +146,9 @@ namespace Volo.Abp.Identity.EntityFrameworkCore CancellationToken cancellationToken = default) { var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToList(); + var dbContext = await GetDbContextAsync(); - return await DbContext.Roles + return await dbContext.Roles .Where(r => !roleIds.Contains(r.Id)) .WhereIf(!filter.IsNullOrWhiteSpace(), r => r.Name.Contains(filter)) .CountAsync(cancellationToken); @@ -155,7 +163,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = CreateGetMembersFilteredQuery(organizationUnit, filter); + var query = await CreateGetMembersFilteredQueryAsync(organizationUnit, filter); return await query.IncludeDetails(includeDetails).OrderBy(sorting ?? nameof(IdentityUser.UserName)) .PageBy(skipCount, maxResultCount) @@ -167,7 +175,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string filter = null, CancellationToken cancellationToken = default) { - var query = CreateGetMembersFilteredQuery(organizationUnit, filter); + var query = await CreateGetMembersFilteredQueryAsync(organizationUnit, filter); return await query.CountAsync(GetCancellationToken(cancellationToken)); } @@ -181,11 +189,13 @@ namespace Volo.Abp.Identity.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var userIdsInOrganizationUnit = DbContext.Set() + var dbContext = await GetDbContextAsync(); + + var userIdsInOrganizationUnit = dbContext.Set() .Where(uou => uou.OrganizationUnitId == organizationUnit.Id) .Select(uou => uou.UserId); - var query = DbContext.Users + var query = dbContext.Users .Where(u => !userIdsInOrganizationUnit.Contains(u.Id)); if (!filter.IsNullOrWhiteSpace()) @@ -209,11 +219,13 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string filter = null, CancellationToken cancellationToken = default) { - var userIdsInOrganizationUnit = DbContext.Set() + var dbContext = await GetDbContextAsync(); + + var userIdsInOrganizationUnit = dbContext.Set() .Where(uou => uou.OrganizationUnitId == organizationUnit.Id) .Select(uou => uou.UserId); - return await DbContext.Users + return await dbContext.Users .Where(u => !userIdsInOrganizationUnit.Contains(u.Id)) .WhereIf(!filter.IsNullOrWhiteSpace(), u => u.UserName.Contains(filter) || @@ -222,11 +234,17 @@ namespace Volo.Abp.Identity.EntityFrameworkCore .CountAsync(cancellationToken); } + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + public override async Task> WithDetailsAsync(params Expression>[] propertySelectors) + { + return (await GetQueryableAsync()).IncludeDetails(); + } + public virtual Task RemoveAllRolesAsync( OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) @@ -239,17 +257,21 @@ namespace Volo.Abp.Identity.EntityFrameworkCore OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) { - var ouMembersQuery = await DbContext.Set() + var dbContext = await GetDbContextAsync(); + + var ouMembersQuery = await dbContext.Set() .Where(q => q.OrganizationUnitId == organizationUnit.Id) .ToListAsync(GetCancellationToken(cancellationToken)); - DbContext.Set().RemoveRange(ouMembersQuery); + dbContext.Set().RemoveRange(ouMembersQuery); } - protected virtual IQueryable CreateGetMembersFilteredQuery(OrganizationUnit organizationUnit, string filter = null) + protected virtual async Task> CreateGetMembersFilteredQueryAsync(OrganizationUnit organizationUnit, string filter = null) { - var query = from userOu in DbContext.Set() - join user in DbContext.Users on userOu.UserId equals user.Id + var dbContext = await GetDbContextAsync(); + + var query = from userOu in dbContext.Set() + join user in dbContext.Users on userOu.UserId equals user.Id where userOu.OrganizationUnitId == organizationUnit.Id select user; diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs index bd4b079a07..de0afd8abc 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoOrganizationUnitRepository.cs @@ -1,9 +1,7 @@ -using MongoDB.Bson; -using MongoDB.Driver; +using MongoDB.Driver; using MongoDB.Driver.Linq; using System; using System.Collections.Generic; -using System.Data; using System.Linq; using System.Linq.Dynamic.Core; using System.Threading; @@ -11,7 +9,6 @@ using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; using Volo.Abp.MultiTenancy; -using Volo.Abp.Uow; namespace Volo.Abp.Identity.MongoDB { @@ -30,7 +27,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(ou => ou.ParentId == parentId) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -41,7 +38,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(ou => ou.Code.StartsWith(code) && ou.Id != parentId.Value) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -51,7 +48,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(t => ids.Contains(t.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -63,7 +60,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .OrderBy(sorting ?? nameof(OrganizationUnit.DisplayName)) .As>() .PageBy>(skipCount, maxResultCount) @@ -75,7 +72,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .OrderBy(x => x.Id) .FirstOrDefaultAsync( ou => ou.DisplayName == displayName, @@ -92,7 +89,10 @@ namespace Volo.Abp.Identity.MongoDB CancellationToken cancellationToken = default) { var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToArray(); - return await ApplyDataFilters, IdentityRole>(DbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id))) + var dbContext = await GetDbContextAsync(cancellationToken); + return await ApplyDataFilters, IdentityRole>( + dbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id)) + ) .OrderBy(sorting ?? nameof(IdentityRole.Name)) .As>() .PageBy>(skipCount, maxResultCount) @@ -104,7 +104,10 @@ namespace Volo.Abp.Identity.MongoDB CancellationToken cancellationToken = default) { var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToArray(); - return await ApplyDataFilters, IdentityRole>( DbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id))) + var dbContext = await GetDbContextAsync(cancellationToken); + return await ApplyDataFilters, IdentityRole>( + dbContext.Roles.AsQueryable().Where(r => roleIds.Contains(r.Id)) + ) .As>() .CountAsync(cancellationToken); } @@ -119,7 +122,8 @@ namespace Volo.Abp.Identity.MongoDB CancellationToken cancellationToken = default) { var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToArray(); - return await ApplyDataFilters, IdentityRole>(DbContext.Roles.AsQueryable()) + var dbContext = await GetDbContextAsync(cancellationToken); + return await ApplyDataFilters, IdentityRole>(dbContext.Roles.AsQueryable()) .Where(r => !roleIds.Contains(r.Id)) .WhereIf(!filter.IsNullOrWhiteSpace(), r => r.Name.Contains(filter)) .OrderBy(sorting ?? nameof(IdentityRole.Name)) @@ -134,7 +138,8 @@ namespace Volo.Abp.Identity.MongoDB CancellationToken cancellationToken = default) { var roleIds = organizationUnit.Roles.Select(r => r.RoleId).ToArray(); - return await ApplyDataFilters, IdentityRole>(DbContext.Roles.AsQueryable()) + var dbContext = await GetDbContextAsync(cancellationToken); + return await ApplyDataFilters, IdentityRole>(dbContext.Roles.AsQueryable()) .Where(r => !roleIds.Contains(r.Id)) .WhereIf(!filter.IsNullOrWhiteSpace(), r => r.Name.Contains(filter)) .As>() @@ -150,13 +155,13 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = CreateGetMembersFilteredQuery(organizationUnit, filter); - + cancellationToken = GetCancellationToken(cancellationToken); + var query = await CreateGetMembersFilteredQueryAsync(organizationUnit, filter, cancellationToken); return await query .OrderBy(sorting ?? nameof(IdentityUser.UserName)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(cancellationToken); } public virtual async Task GetMembersCountAsync( @@ -164,9 +169,9 @@ namespace Volo.Abp.Identity.MongoDB string filter = null, CancellationToken cancellationToken = default) { - var query = CreateGetMembersFilteredQuery(organizationUnit, filter); - - return await query.CountAsync(GetCancellationToken(cancellationToken)); + cancellationToken = GetCancellationToken(cancellationToken); + var query = await CreateGetMembersFilteredQueryAsync(organizationUnit, filter, cancellationToken); + return await query.CountAsync(cancellationToken); } public async Task> GetUnaddedUsersAsync( @@ -178,7 +183,8 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await ApplyDataFilters, IdentityUser>(DbContext.Users.AsQueryable()) + var dbContext = await GetDbContextAsync(cancellationToken); + return await ApplyDataFilters, IdentityUser>(dbContext.Users.AsQueryable()) .Where(u => !u.OrganizationUnits.Any(uou => uou.OrganizationUnitId == organizationUnit.Id)) .WhereIf>( !filter.IsNullOrWhiteSpace(), @@ -196,7 +202,8 @@ namespace Volo.Abp.Identity.MongoDB public async Task GetUnaddedUsersCountAsync(OrganizationUnit organizationUnit, string filter = null, CancellationToken cancellationToken = default) { - return await ApplyDataFilters, IdentityUser>(DbContext.Users.AsQueryable()) + var dbContext = await GetDbContextAsync(cancellationToken); + return await ApplyDataFilters, IdentityUser>(dbContext.Users.AsQueryable()) .Where(u => !u.OrganizationUnits.Any(uou => uou.OrganizationUnitId == organizationUnit.Id)) .WhereIf>( !filter.IsNullOrWhiteSpace(), @@ -217,7 +224,8 @@ namespace Volo.Abp.Identity.MongoDB public virtual async Task RemoveAllMembersAsync(OrganizationUnit organizationUnit, CancellationToken cancellationToken = default) { - var users = await ApplyDataFilters, IdentityUser>(DbContext.Users.AsQueryable()) + var dbContext = await GetDbContextAsync(cancellationToken); + var users = await ApplyDataFilters, IdentityUser>(dbContext.Users.AsQueryable()) .Where(u => u.OrganizationUnits.Any(uou => uou.OrganizationUnitId == organizationUnit.Id)) .As>() .ToListAsync(GetCancellationToken(cancellationToken)); @@ -225,13 +233,17 @@ namespace Volo.Abp.Identity.MongoDB foreach (var user in users) { user.RemoveOrganizationUnit(organizationUnit.Id); - DbContext.Users.ReplaceOne(u => u.Id == user.Id, user); + await dbContext.Users.ReplaceOneAsync(u => u.Id == user.Id, user, cancellationToken: cancellationToken); } } - protected virtual IMongoQueryable CreateGetMembersFilteredQuery(OrganizationUnit organizationUnit, string filter = null) + protected virtual async Task> CreateGetMembersFilteredQueryAsync( + OrganizationUnit organizationUnit, + string filter = null, + CancellationToken cancellationToken = default) { - return ApplyDataFilters, IdentityUser>(DbContext.Users.AsQueryable()) + var dbContext = await GetDbContextAsync(cancellationToken); + return ApplyDataFilters, IdentityUser>(dbContext.Users.AsQueryable()) .Where(u => u.OrganizationUnits.Any(uou => uou.OrganizationUnitId == organizationUnit.Id)) .WhereIf>( !filter.IsNullOrWhiteSpace(), From ee7d9adb4d7014152b69f232a377f229a80683b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 21 Dec 2020 17:33:26 +0300 Subject: [PATCH 04/83] Fix naming --- .../Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs index acd414af83..f8cdbb3599 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs @@ -181,14 +181,14 @@ namespace Volo.Abp.Uow.EntityFrameworkCore { var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); - var dbtransaction = unitOfWork.Options.IsolationLevel.HasValue + var dbTransaction = unitOfWork.Options.IsolationLevel.HasValue ? await dbContext.Database.BeginTransactionAsync(unitOfWork.Options.IsolationLevel.Value) : await dbContext.Database.BeginTransactionAsync(); unitOfWork.AddTransactionApi( transactionApiKey, new EfCoreTransactionApi( - dbtransaction, + dbTransaction, dbContext ) ); From c2c25a091ac1be9654c310da59c66f88dc0110d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 21 Dec 2020 17:33:40 +0300 Subject: [PATCH 05/83] Override true base method. --- .../EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs index c3a8975fec..6a54f41959 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreOrganizationUnitRepository.cs @@ -240,7 +240,7 @@ namespace Volo.Abp.Identity.EntityFrameworkCore return GetQueryable().IncludeDetails(); } - public override async Task> WithDetailsAsync(params Expression>[] propertySelectors) + public override async Task> WithDetailsAsync() { return (await GetQueryableAsync()).IncludeDetails(); } From 06889783f8c9e1c07c85847522ad7a760e4df621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 21 Dec 2020 18:03:23 +0300 Subject: [PATCH 06/83] Apply async changes for EF Core repos. --- .../EfCoreFeatureValueRepository.cs | 6 +-- .../MongoDB/MongoFeatureValueRepository.cs | 6 +-- .../ApiResources/ApiResourceRepository.cs | 34 +++++++----- .../ApiScopes/ApiScopeRepository.cs | 25 +++++---- .../Clients/ClientRepository.cs | 52 +++++++++++-------- .../Devices/DeviceFlowCodesRepository.cs | 6 +-- .../Grants/PersistedGrantRepository.cs | 18 ++++--- .../IdentityResourceRepository.cs | 14 +++-- .../EfCorePermissionGrantRepository.cs | 6 +-- .../MongoDb/MongoPermissionGrantRepository.cs | 15 +++--- .../EfCoreSettingRepository.cs | 6 +-- .../MongoDB/MongoSettingRepository.cs | 12 +++-- .../EfCoreAbpUserRepositoryBase.cs | 8 +-- .../Users/MongoDB/MongoUserRepositoryBase.cs | 20 ++++--- 14 files changed, 139 insertions(+), 89 deletions(-) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs index c559851bf1..be75e600d8 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.FeatureManagement.EntityFrameworkCore public virtual async Task FindAsync(string name, string providerName, string providerKey) { - return await DbSet + return await (await GetDbSetAsync()) .OrderBy(x => x.Id) .FirstOrDefaultAsync( s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey @@ -26,7 +26,7 @@ namespace Volo.Abp.FeatureManagement.EntityFrameworkCore public async Task> FindAllAsync(string name, string providerName, string providerKey) { - return await DbSet + return await (await GetDbSetAsync()) .Where( s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey ).ToListAsync(); @@ -34,7 +34,7 @@ namespace Volo.Abp.FeatureManagement.EntityFrameworkCore public virtual async Task> GetListAsync(string providerName, string providerKey) { - return await DbSet + return await (await GetDbSetAsync()) .Where( s => s.ProviderName == providerName && s.ProviderKey == providerKey ).ToListAsync(); diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs index 2b96ca876a..21d4784f6e 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs @@ -18,20 +18,20 @@ namespace Volo.Abp.FeatureManagement.MongoDB public virtual async Task FindAsync(string name, string providerName, string providerKey) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync()) .OrderBy(x => x.Id) .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey); } public async Task> FindAllAsync(string name, string providerName, string providerKey) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync()) .Where(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(); } public virtual async Task> GetListAsync(string providerName, string providerKey) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync()) .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey) .ToListAsync(); } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs index 3cdcb7e49d..16a789048d 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiResources/ApiResourceRepository.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.IdentityServer.ApiResources public async Task FindByNameAsync(string apiResourceName, bool includeDetails = true, CancellationToken cancellationToken = default) { - var query = from apiResource in DbSet.IncludeDetails(includeDetails) + var query = from apiResource in (await GetDbSetAsync()).IncludeDetails(includeDetails) where apiResource.Name == apiResourceName orderby apiResource.Id select apiResource; @@ -31,7 +31,7 @@ namespace Volo.Abp.IdentityServer.ApiResources public async Task> FindByNameAsync(string[] apiResourceNames, bool includeDetails = true, CancellationToken cancellationToken = default) { - var query = from apiResource in DbSet.IncludeDetails(includeDetails) + var query = from apiResource in (await GetDbSetAsync()).IncludeDetails(includeDetails) where apiResourceNames.Contains(apiResource.Name) orderby apiResource.Name select apiResource; @@ -44,7 +44,7 @@ namespace Volo.Abp.IdentityServer.ApiResources bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = from api in DbSet.IncludeDetails(includeDetails) + var query = from api in (await GetDbSetAsync()).IncludeDetails(includeDetails) where api.Scopes.Any(x => scopeNames.Contains(x.Scope)) select api; @@ -58,7 +58,7 @@ namespace Volo.Abp.IdentityServer.ApiResources bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.Description.Contains(filter) || @@ -70,41 +70,49 @@ namespace Volo.Abp.IdentityServer.ApiResources public virtual async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync(ar => ar.Id != expectedId && ar.Name == name, GetCancellationToken(cancellationToken)); + return await (await GetDbSetAsync()).AnyAsync(ar => ar.Id != expectedId && ar.Name == name, GetCancellationToken(cancellationToken)); } public async override Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = default) { - var resourceClaims = DbContext.Set().Where(sc => sc.ApiResourceId == id); + var dbContext = await GetDbContextAsync(); + + var resourceClaims = dbContext.Set().Where(sc => sc.ApiResourceId == id); foreach (var scopeClaim in resourceClaims) { - DbContext.Set().Remove(scopeClaim); + dbContext.Set().Remove(scopeClaim); } - var resourceScopes = DbContext.Set().Where(s => s.ApiResourceId == id); + var resourceScopes = dbContext.Set().Where(s => s.ApiResourceId == id); foreach (var scope in resourceScopes) { - DbContext.Set().Remove(scope); + dbContext.Set().Remove(scope); } - var resourceSecrets = DbContext.Set().Where(s => s.ApiResourceId == id); + var resourceSecrets = dbContext.Set().Where(s => s.ApiResourceId == id); foreach (var secret in resourceSecrets) { - DbContext.Set().Remove(secret); + dbContext.Set().Remove(secret); } - var apiResourceProperties = DbContext.Set().Where(s => s.ApiResourceId == id); + var apiResourceProperties = dbContext.Set().Where(s => s.ApiResourceId == id); foreach (var property in apiResourceProperties) { - DbContext.Set().Remove(property); + dbContext.Set().Remove(property); } await base.DeleteAsync(id, autoSave, cancellationToken); } + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiScopes/ApiScopeRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiScopes/ApiScopeRepository.cs index c2a962ead6..4cece3209e 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiScopes/ApiScopeRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/ApiScopes/ApiScopeRepository.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.IdentityServer.ApiScopes public async Task GetByNameAsync(string scopeName, bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .OrderBy(x=>x.Id) .FirstOrDefaultAsync(x => x.Name == scopeName, GetCancellationToken(cancellationToken)); } @@ -28,7 +28,7 @@ namespace Volo.Abp.IdentityServer.ApiScopes public async Task> GetListByNameAsync(string[] scopeNames, bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = from scope in DbSet.IncludeDetails(includeDetails) + var query = from scope in (await GetDbSetAsync()).IncludeDetails(includeDetails) where scopeNames.Contains(scope.Name) orderby scope.Id select scope; @@ -38,7 +38,7 @@ namespace Volo.Abp.IdentityServer.ApiScopes public async Task> GetListAsync(string sorting, int skipCount, int maxResultCount, string filter = null, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.Description.Contains(filter) || @@ -50,29 +50,36 @@ namespace Volo.Abp.IdentityServer.ApiScopes public async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync(x => x.Id != expectedId && x.Name == name, GetCancellationToken(cancellationToken)); + return await (await GetDbSetAsync()).AnyAsync(x => x.Id != expectedId && x.Name == name, GetCancellationToken(cancellationToken)); } - public async override Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = new CancellationToken()) + public override async Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = new CancellationToken()) { - var scopeClaims = DbContext.Set().Where(sc => sc.ApiScopeId == id); + var dbContext = await GetDbContextAsync(); + var scopeClaims = dbContext.Set().Where(sc => sc.ApiScopeId == id); foreach (var claim in scopeClaims) { - DbContext.Set().Remove(claim); + dbContext.Set().Remove(claim); } - var scopeProperties = DbContext.Set().Where(s => s.ApiScopeId == id); + var scopeProperties = dbContext.Set().Where(s => s.ApiScopeId == id); foreach (var property in scopeProperties) { - DbContext.Set().Remove(property); + dbContext.Set().Remove(property); } await base.DeleteAsync(id, autoSave, cancellationToken); } + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs index 671d98d822..7607a189ca 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.IdentityServer.Clients bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .OrderBy(x => x.ClientId) .FirstOrDefaultAsync(x => x.ClientId == clientId, GetCancellationToken(cancellationToken)); @@ -33,7 +33,7 @@ namespace Volo.Abp.IdentityServer.Clients string sorting, int skipCount, int maxResultCount, string filter, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.ClientId.Contains(filter)) .OrderBy(sorting ?? nameof(Client.ClientName) + " desc") @@ -43,7 +43,7 @@ namespace Volo.Abp.IdentityServer.Clients public virtual async Task> GetAllDistinctAllowedCorsOriginsAsync(CancellationToken cancellationToken = default) { - return await DbContext.ClientCorsOrigins + return await (await GetDbContextAsync()).ClientCorsOrigins .Select(x => x.Origin) .Distinct() .ToListAsync(GetCancellationToken(cancellationToken)); @@ -51,62 +51,70 @@ namespace Volo.Abp.IdentityServer.Clients public virtual async Task CheckClientIdExistAsync(string clientId, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken); + return await (await GetDbSetAsync()).AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken); } public async override Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = default) { - foreach (var clientGrantType in DbContext.Set().Where(x => x.ClientId == id)) + var dbContext = await GetDbContextAsync(); + + foreach (var clientGrantType in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientGrantType); + dbContext.Set().Remove(clientGrantType); } - foreach (var clientRedirectUri in DbContext.Set().Where(x => x.ClientId == id)) + foreach (var clientRedirectUri in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientRedirectUri); + dbContext.Set().Remove(clientRedirectUri); } - foreach (var clientPostLogoutRedirectUri in DbContext.Set().Where(x => x.ClientId == id)) + foreach (var clientPostLogoutRedirectUri in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientPostLogoutRedirectUri); + dbContext.Set().Remove(clientPostLogoutRedirectUri); } - foreach (var clientScope in DbContext.Set().Where(x => x.ClientId == id)) + foreach (var clientScope in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientScope); + dbContext.Set().Remove(clientScope); } - foreach (var clientSecret in DbContext.Set().Where(x => x.ClientId == id)) + foreach (var clientSecret in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientSecret); + dbContext.Set().Remove(clientSecret); } - foreach (var clientClaim in DbContext.Set().Where(x => x.ClientId == id)) + foreach (var clientClaim in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientClaim); + dbContext.Set().Remove(clientClaim); } - foreach (var clientIdPRestriction in DbContext.Set().Where(x => x.ClientId == id)) + foreach (var clientIdPRestriction in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientIdPRestriction); + dbContext.Set().Remove(clientIdPRestriction); } - foreach (var clientCorsOrigin in DbContext.Set().Where(x => x.ClientId == id)) + foreach (var clientCorsOrigin in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientCorsOrigin); + dbContext.Set().Remove(clientCorsOrigin); } - foreach (var clientProperty in DbContext.Set().Where(x => x.ClientId == id)) + foreach (var clientProperty in dbContext.Set().Where(x => x.ClientId == id)) { - DbContext.Set().Remove(clientProperty); + dbContext.Set().Remove(clientProperty); } await base.DeleteAsync(id, autoSave, cancellationToken); } + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs index 819c90d402..a6fd6e196b 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Devices/DeviceFlowCodesRepository.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.IdentityServer.Devices string userCode, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(d => d.UserCode == userCode) .OrderBy(d => d.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -33,7 +33,7 @@ namespace Volo.Abp.IdentityServer.Devices string deviceCode, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(d => d.DeviceCode == deviceCode) .OrderBy(d => d.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -42,7 +42,7 @@ namespace Volo.Abp.IdentityServer.Devices public virtual async Task> GetListByExpirationAsync(DateTime maxExpirationDate, int maxResultCount, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(x => x.Expiration != null && x.Expiration < maxExpirationDate) .OrderBy(x => x.ClientId) .Take(maxResultCount) diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs index aa7a27804f..2dbdfc1a3b 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Grants/PersistedGrantRepository.cs @@ -21,7 +21,7 @@ namespace Volo.Abp.IdentityServer.Grants public async Task> GetListAsync(string subjectId, string sessionId, string clientId, string type, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await Filter(subjectId, sessionId, clientId, type) + return await (await FilterAsync(subjectId, sessionId, clientId, type)) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -29,7 +29,7 @@ namespace Volo.Abp.IdentityServer.Grants string key, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(x => x.Key == key) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -39,7 +39,7 @@ namespace Volo.Abp.IdentityServer.Grants string subjectId, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(x => x.SubjectId == subjectId) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -49,7 +49,7 @@ namespace Volo.Abp.IdentityServer.Grants int maxResultCount, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(x => x.Expiration != null && x.Expiration < maxExpirationDate) .OrderBy(x => x.ClientId) .Take(maxResultCount) @@ -63,21 +63,23 @@ namespace Volo.Abp.IdentityServer.Grants string type = null, CancellationToken cancellationToken = default) { - var persistedGrants = await Filter(subjectId, sessionId, clientId, type).ToListAsync(GetCancellationToken(cancellationToken)); + var persistedGrants = await (await FilterAsync(subjectId, sessionId, clientId, type)).ToListAsync(GetCancellationToken(cancellationToken)); + + var dbSet = await GetDbSetAsync(); foreach (var persistedGrant in persistedGrants) { - DbSet.Remove(persistedGrant); + dbSet.Remove(persistedGrant); } } - private IQueryable Filter( + private async Task> FilterAsync( string subjectId, string sessionId, string clientId, string type) { - return DbSet + return (await GetDbSetAsync()) .WhereIf(!subjectId.IsNullOrWhiteSpace(), x => x.SubjectId == subjectId) .WhereIf(!sessionId.IsNullOrWhiteSpace(), x => x.SessionId == sessionId) .WhereIf(!clientId.IsNullOrWhiteSpace(), x => x.ClientId == clientId) diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs index 6ddf38e2db..1b83b46158 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceRepository.cs @@ -24,22 +24,28 @@ namespace Volo.Abp.IdentityServer.IdentityResources bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = from identityResource in DbSet.IncludeDetails(includeDetails) + var query = from identityResource in (await GetDbSetAsync()).IncludeDetails(includeDetails) where scopeNames.Contains(identityResource.Name) select identityResource; return await query.ToListAsync(GetCancellationToken(cancellationToken)); } + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } + public virtual async Task> GetListAsync(string sorting, int skipCount, int maxResultCount, string filter, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.Description.Contains(filter) || @@ -54,7 +60,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .Where(x => x.Name == name) .OrderBy(x => x.Id) @@ -63,7 +69,7 @@ namespace Volo.Abp.IdentityServer.IdentityResources public virtual async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync(ir => ir.Id != expectedId && ir.Name == name, cancellationToken: cancellationToken); + return await (await GetDbSetAsync()).AnyAsync(ir => ir.Id != expectedId && ir.Name == name, cancellationToken: cancellationToken); } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs index 5a479c348b..bc0ea04cf2 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore string providerKey, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .OrderBy(x => x.Id) .FirstOrDefaultAsync(s => s.Name == name && @@ -39,7 +39,7 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore string providerKey, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey @@ -49,7 +49,7 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .Where(s => names.Contains(s.Name) && s.ProviderName == providerName && diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs index a8f95ee6b9..823d5e63a3 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs @@ -24,13 +24,14 @@ namespace Volo.Abp.PermissionManagement.MongoDB string providerKey, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) .OrderBy(x => x.Id) .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey, - GetCancellationToken(cancellationToken) + cancellationToken ); } @@ -39,22 +40,24 @@ namespace Volo.Abp.PermissionManagement.MongoDB string providerKey, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey - ).ToListAsync(GetCancellationToken(cancellationToken)); + ).ToListAsync(cancellationToken); } public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey - ).ToListAsync(GetCancellationToken(cancellationToken)); + ).ToListAsync(cancellationToken); } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs index c3323f331e..e90d2fc63a 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.SettingManagement.EntityFrameworkCore public virtual async Task FindAsync(string name, string providerName, string providerKey) { - return await DbSet + return await (await GetDbSetAsync()) .OrderBy(x => x.Id) .FirstOrDefaultAsync( s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey @@ -26,7 +26,7 @@ namespace Volo.Abp.SettingManagement.EntityFrameworkCore public virtual async Task> GetListAsync(string providerName, string providerKey) { - return await DbSet + return await (await GetDbSetAsync()) .Where( s => s.ProviderName == providerName && s.ProviderKey == providerKey ).ToListAsync(); @@ -34,7 +34,7 @@ namespace Volo.Abp.SettingManagement.EntityFrameworkCore public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey) { - return await DbSet + return await (await GetDbSetAsync()) .Where( s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey ).ToListAsync(); diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs index 1acaf50d56..e81e76dfcc 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs @@ -19,17 +19,23 @@ namespace Volo.Abp.SettingManagement.MongoDB public virtual async Task FindAsync(string name, string providerName, string providerKey) { - return await GetMongoQueryable().OrderBy(x => x.Id).FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey); + return await (await GetMongoQueryableAsync()) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey); } public virtual async Task> GetListAsync(string providerName, string providerKey) { - return await GetMongoQueryable().Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(); + return await (await GetMongoQueryableAsync()) + .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey) + .ToListAsync(); } public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey) { - return await GetMongoQueryable().Where(s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(); + return await (await GetMongoQueryableAsync()) + .Where(s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey) + .ToListAsync(); } } } diff --git a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs index 87a8fbc507..de27a05fbd 100644 --- a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs +++ b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/EfCoreAbpUserRepositoryBase.cs @@ -27,7 +27,9 @@ namespace Volo.Abp.Users.EntityFrameworkCore public virtual async Task> GetListAsync(IEnumerable ids, CancellationToken cancellationToken = default) { - return await DbSet.Where(u => ids.Contains(u.Id)).ToListAsync(GetCancellationToken(cancellationToken)); + return await (await GetDbSetAsync()) + .Where(u => ids.Contains(u.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); } public async Task> SearchAsync( @@ -37,7 +39,7 @@ namespace Volo.Abp.Users.EntityFrameworkCore string filter = null, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .WhereIf( !filter.IsNullOrWhiteSpace(), u => @@ -55,7 +57,7 @@ namespace Volo.Abp.Users.EntityFrameworkCore string filter = null, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .WhereIf( !filter.IsNullOrWhiteSpace(), u => diff --git a/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs b/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs index cf4d860def..996b6e314c 100644 --- a/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs +++ b/modules/users/src/Volo.Abp.Users.MongoDB/Volo/Abp/Users/MongoDB/MongoUserRepositoryBase.cs @@ -23,12 +23,18 @@ namespace Volo.Abp.Users.MongoDB public virtual async Task FindByUserNameAsync(string userName, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().OrderBy(x => x.Id).FirstOrDefaultAsync(u => u.UserName == userName, GetCancellationToken(cancellationToken)); + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync(u => u.UserName == userName, cancellationToken); } public virtual async Task> GetListAsync(IEnumerable ids, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().Where(u => ids.Contains(u.Id)).ToListAsync(GetCancellationToken(cancellationToken)); + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) + .Where(u => ids.Contains(u.Id)) + .ToListAsync(cancellationToken); } public async Task> SearchAsync( @@ -38,7 +44,8 @@ namespace Volo.Abp.Users.MongoDB string filter = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf>( !filter.IsNullOrWhiteSpace(), u => @@ -50,12 +57,13 @@ namespace Volo.Abp.Users.MongoDB .OrderBy(sorting ?? nameof(IUserData.UserName)) .As>() .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(cancellationToken); } public async Task GetCountAsync(string filter = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf>( !filter.IsNullOrWhiteSpace(), u => @@ -64,7 +72,7 @@ namespace Volo.Abp.Users.MongoDB u.Name.Contains(filter) || u.Surname.Contains(filter) ) - .LongCountAsync(GetCancellationToken(cancellationToken)); + .LongCountAsync(cancellationToken); } } } From 7642a39478486f25ca7c5c7cbd19a5da1355afe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 21 Dec 2020 20:39:21 +0300 Subject: [PATCH 07/83] Fix EfCoreIdentityUserRepository: Use GetDbSetAsync --- .../EntityFrameworkCore/EfCoreIdentityUserRepository.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index 853e980f01..8fcce7c35a 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -188,7 +188,8 @@ namespace Volo.Abp.Identity.EntityFrameworkCore string filter = null, CancellationToken cancellationToken = default) { - return await this.WhereIf( + return await (await GetDbSetAsync()) + .WhereIf( !filter.IsNullOrWhiteSpace(), u => u.UserName.Contains(filter) || From 64f9ee3c7cf8b635923ed8dcba6f6349da348bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 21 Dec 2020 20:39:38 +0300 Subject: [PATCH 08/83] Add warning log. --- .../Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs | 2 ++ .../EntityFrameworkCore/UnitOfWorkDbContextProvider.cs | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs index 17af400b97..b35436cfbc 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IDbContextProvider.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; namespace Volo.Abp.EntityFrameworkCore @@ -5,6 +6,7 @@ namespace Volo.Abp.EntityFrameworkCore public interface IDbContextProvider where TDbContext : IEfCoreDbContext { + [Obsolete("Use GetDbContextAsync method.")] TDbContext GetDbContext(); Task GetDbContextAsync(); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs index f8cdbb3599..a5e9a311db 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.DependencyInjection; @@ -14,6 +16,8 @@ namespace Volo.Abp.Uow.EntityFrameworkCore public class UnitOfWorkDbContextProvider : IDbContextProvider where TDbContext : IEfCoreDbContext { + public ILogger> Logger { get; set; } + private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IConnectionStringResolver _connectionStringResolver; @@ -23,10 +27,16 @@ namespace Volo.Abp.Uow.EntityFrameworkCore { _unitOfWorkManager = unitOfWorkManager; _connectionStringResolver = connectionStringResolver; + + Logger = NullLogger>.Instance; } + [Obsolete("Use GetDbContextAsync method.")] public TDbContext GetDbContext() { + Logger.LogWarning("UnitOfWorkDbContextProvider.GetDbContext is deprecated. Use GetDbContextAsync instead!"); + Logger.LogWarning(Environment.StackTrace); + var unitOfWork = _unitOfWorkManager.Current; if (unitOfWork == null) { From 9994bbcf5346afcd67d7dadd6913dd2f4c4daa8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 22 Dec 2020 12:09:38 +0300 Subject: [PATCH 09/83] Use reserved UOW also for the UOW interceptor. Also, allow web layer to determine transaction behaviour. --- .../AspNetCore/Mvc/Uow/AbpUowActionFilter.cs | 2 +- .../AspNetCore/Mvc/Uow/AbpUowPageFilter.cs | 2 +- .../AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs | 4 +- ...eUnitOfWorkTransactionBehaviourProvider.cs | 41 +++++++++++++++++++ .../UnitOfWorkDbContextProvider.cs | 2 + ...IUnitOfWorkTransactionBehaviourProvider.cs | 7 ++++ ...lUnitOfWorkTransactionBehaviourProvider.cs | 9 ++++ .../Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs | 4 +- .../Volo/Abp/Uow/UnitOfWorkInterceptor.cs | 21 ++++++++-- 9 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs create mode 100644 framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkTransactionBehaviourProvider.cs create mode 100644 framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkTransactionBehaviourProvider.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs index 552ce7e04e..43dedf916f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs @@ -46,7 +46,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow var options = CreateOptions(context, unitOfWorkAttr); //Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware - if (_unitOfWorkManager.TryBeginReserved(AbpUnitOfWorkMiddleware.UnitOfWorkReservationName, options)) + if (_unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options)) { var result = await next(); if (!Succeed(result)) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs index bcef10ecd4..960c47b591 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs @@ -50,7 +50,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow var options = CreateOptions(context, unitOfWorkAttr); //Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware - if (_unitOfWorkManager.TryBeginReserved(AbpUnitOfWorkMiddleware.UnitOfWorkReservationName, options)) + if (_unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options)) { var result = await next(); if (!Succeed(result)) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs index c9ac1be509..aeb6f8a8c0 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs @@ -7,8 +7,6 @@ namespace Volo.Abp.AspNetCore.Uow { public class AbpUnitOfWorkMiddleware : IMiddleware, ITransientDependency { - public const string UnitOfWorkReservationName = "_AbpActionUnitOfWork"; - private readonly IUnitOfWorkManager _unitOfWorkManager; public AbpUnitOfWorkMiddleware(IUnitOfWorkManager unitOfWorkManager) @@ -18,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Uow public async Task InvokeAsync(HttpContext context, RequestDelegate next) { - using (var uow = _unitOfWorkManager.Reserve(UnitOfWorkReservationName)) + using (var uow = _unitOfWorkManager.Reserve(UnitOfWork.UnitOfWorkReservationName)) { await next(context); await uow.CompleteAsync(context.RequestAborted); diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs new file mode 100644 index 0000000000..061bc62018 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.Net.Http; +using Microsoft.AspNetCore.Http; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Uow; + +namespace Volo.Abp.AspNetCore.Uow +{ + public class AspNetCoreUnitOfWorkTransactionBehaviourProvider : IUnitOfWorkTransactionBehaviourProvider, ITransientDependency + { + private readonly IHttpContextAccessor _httpContextAccessor; + + public virtual bool? IsTransactional + { + get + { + var httpContext = _httpContextAccessor.HttpContext; + if (httpContext == null) + { + return null; + } + + //IdentityServer endpoint (TODO: Better to move to the IDS module) + if (httpContext.Request.Path.Value?.StartsWith("/connect/", StringComparison.OrdinalIgnoreCase) == true) + { + return false; + } + + return !string.Equals( + httpContext.Request.Method, + HttpMethod.Get.Method, StringComparison.OrdinalIgnoreCase + ); + } + } + + public AspNetCoreUnitOfWorkTransactionBehaviourProvider(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs index a5e9a311db..22df5fddf5 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs @@ -133,6 +133,8 @@ namespace Volo.Abp.Uow.EntityFrameworkCore private async Task CreateDbContextAsync(IUnitOfWork unitOfWork) { + Logger.LogDebug($"Creating a new DbContext of type {typeof(TDbContext).FullName}"); + return unitOfWork.Options.IsTransactional ? await CreateDbContextWithTransactionAsync(unitOfWork) : unitOfWork.ServiceProvider.GetRequiredService(); diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkTransactionBehaviourProvider.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkTransactionBehaviourProvider.cs new file mode 100644 index 0000000000..1db7dac938 --- /dev/null +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkTransactionBehaviourProvider.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.Uow +{ + public interface IUnitOfWorkTransactionBehaviourProvider + { + bool? IsTransactional { get; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkTransactionBehaviourProvider.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkTransactionBehaviourProvider.cs new file mode 100644 index 0000000000..2b302d303a --- /dev/null +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkTransactionBehaviourProvider.cs @@ -0,0 +1,9 @@ +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Uow +{ + public class NullUnitOfWorkTransactionBehaviourProvider : IUnitOfWorkTransactionBehaviourProvider, ISingletonDependency + { + public bool? IsTransactional => null; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index b4158229fe..d53acc8f66 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -11,6 +11,8 @@ namespace Volo.Abp.Uow { public class UnitOfWork : IUnitOfWork, ITransientDependency { + public const string UnitOfWorkReservationName = "_AbpActionUnitOfWork"; + public Guid Id { get; } = Guid.NewGuid(); public IAbpUnitOfWorkOptions Options { get; private set; } @@ -302,7 +304,7 @@ namespace Volo.Abp.Uow } } } - + protected virtual async Task CommitTransactionsAsync() { foreach (var transaction in GetAllActiveTransactionApis()) diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs index f5afcea494..f2ed948eb1 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs @@ -10,11 +10,16 @@ namespace Volo.Abp.Uow public class UnitOfWorkInterceptor : AbpInterceptor, ITransientDependency { private readonly IUnitOfWorkManager _unitOfWorkManager; + private readonly IUnitOfWorkTransactionBehaviourProvider _transactionBehaviourProvider; private readonly AbpUnitOfWorkDefaultOptions _defaultOptions; - public UnitOfWorkInterceptor(IUnitOfWorkManager unitOfWorkManager, IOptions options) + public UnitOfWorkInterceptor( + IUnitOfWorkManager unitOfWorkManager, + IOptions options, + IUnitOfWorkTransactionBehaviourProvider transactionBehaviourProvider) { _unitOfWorkManager = unitOfWorkManager; + _transactionBehaviourProvider = transactionBehaviourProvider; _defaultOptions = options.Value; } @@ -26,7 +31,16 @@ namespace Volo.Abp.Uow return; } - using (var uow = _unitOfWorkManager.Begin(CreateOptions(invocation, unitOfWorkAttribute))) + var options = CreateOptions(invocation, unitOfWorkAttribute); + + //Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware + if (_unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options)) + { + await invocation.ProceedAsync(); + return; + } + + using (var uow = _unitOfWorkManager.Begin(options)) { await invocation.ProceedAsync(); await uow.CompleteAsync(); @@ -42,7 +56,8 @@ namespace Volo.Abp.Uow if (unitOfWorkAttribute?.IsTransactional == null) { options.IsTransactional = _defaultOptions.CalculateIsTransactional( - autoValue: !invocation.Method.Name.StartsWith("Get", StringComparison.InvariantCultureIgnoreCase) + autoValue: _transactionBehaviourProvider.IsTransactional + ?? !invocation.Method.Name.StartsWith("Get", StringComparison.InvariantCultureIgnoreCase) ); } From 482f51bb19af637bfa151a2a0304103810cc5242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 22 Dec 2020 20:46:11 +0300 Subject: [PATCH 10/83] Switch to local ABP and disable transactions --- .../AbpPerfTest.WithAbp/AbpPerfTest.WithAbp.csproj | 6 +++--- test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs | 2 +- test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/AbpPerfTest/AbpPerfTest.WithAbp/AbpPerfTest.WithAbp.csproj b/test/AbpPerfTest/AbpPerfTest.WithAbp/AbpPerfTest.WithAbp.csproj index b270d019a4..3c738143b7 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithAbp/AbpPerfTest.WithAbp.csproj +++ b/test/AbpPerfTest/AbpPerfTest.WithAbp/AbpPerfTest.WithAbp.csproj @@ -5,9 +5,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs b/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs index 3846cdd3de..1cd88989e6 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs +++ b/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs @@ -33,7 +33,7 @@ namespace AbpPerfTest.WithAbp Configure(options => { - options.TransactionBehavior = UnitOfWorkTransactionBehavior.Auto; + options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; }); } diff --git a/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx b/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx index e532423147..70897c49da 100644 --- a/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx +++ b/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx @@ -18,7 +18,7 @@ false 100 - 100 + 1000 10 false From 49d3052258263100f28bdc583549c6a0d0e9ab8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 22 Dec 2020 20:53:35 +0300 Subject: [PATCH 11/83] Enable transaction --- test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs | 2 +- test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx | 4 ++-- test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs b/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs index 1cd88989e6..3846cdd3de 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs +++ b/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs @@ -33,7 +33,7 @@ namespace AbpPerfTest.WithAbp Configure(options => { - options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; + options.TransactionBehavior = UnitOfWorkTransactionBehavior.Auto; }); } diff --git a/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx b/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx index 70897c49da..947feb54f7 100644 --- a/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx +++ b/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx @@ -16,9 +16,9 @@ continue false - 100 + 20 - 1000 + 2000 10 false diff --git a/test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx b/test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx index 05dbaeacf8..832d8e05d0 100644 --- a/test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx +++ b/test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx @@ -16,9 +16,9 @@ continue false - 100 + 20 - 100 + 1000 10 false From b38084f0715752888b28b987a356645efe065236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 15:24:12 +0300 Subject: [PATCH 12/83] Resolve warnings. --- .../AuthorizationOptionsExtensions.cs | 6 ++-- .../Permissions/PermissionDefinition.cs | 16 ++++----- .../Permissions/PermissionGroupDefinition.cs | 10 +++--- .../Abp/BackgroundJobs/IAsyncBackgroundJob.cs | 4 +-- .../Volo/Abp/BackgroundJobs/IBackgroundJob.cs | 4 +-- .../BlobContainerFactoryExtensions.cs | 3 +- .../System/AbpStringExtensions.cs | 2 +- .../Generic/AbpCollectionExtensions.cs | 2 +- .../Volo/Abp/Reflection/TypeFinder.cs | 4 +-- .../FormattedStringValueExtracter.cs | 6 ++-- .../Volo/Abp/Data/DataSeedContext.cs | 6 ++-- ...mmonDbContextRegistrationOptionsBuilder.cs | 6 ++-- .../Volo/Abp/EventBus/IEventBus.cs | 4 +-- .../Abp/EventBus/IEventDataMayHaveTenantId.cs | 4 +-- .../Volo/Abp/Features/FeatureDefinition.cs | 4 +-- .../Abp/Features/FeatureGroupDefinition.cs | 8 ++--- .../Volo/Abp/Uow/UnitOfWorkFailedEventArgs.cs | 4 +-- .../AbpAutoMapperModule_Basic_Tests.cs | 4 +-- .../Volo/Abp/Uow/UnitOfWork_Events_Tests.cs | 34 +++++++++++++++---- 19 files changed, 75 insertions(+), 56 deletions(-) diff --git a/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AuthorizationOptionsExtensions.cs b/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AuthorizationOptionsExtensions.cs index 499c2431c5..516e842563 100644 --- a/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AuthorizationOptionsExtensions.cs +++ b/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AuthorizationOptionsExtensions.cs @@ -11,9 +11,9 @@ namespace Microsoft.AspNetCore.Authorization /// /// Gets all policies. - /// + /// /// IMPORTANT NOTE: Use this method carefully. - /// It relies on reflection to get all policies from a private field of the . + /// It relies on reflection to get all policies from a private field of the . /// This method may be removed in the future if internals of changes. /// /// @@ -23,4 +23,4 @@ namespace Microsoft.AspNetCore.Authorization return ((IDictionary) PolicyMapProperty.GetValue(options)).Keys.ToList(); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs index 602fdd9c50..38873fe1b8 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs @@ -54,7 +54,7 @@ namespace Volo.Abp.Authorization.Permissions /// /// Disabling a permission would be helpful to hide a related application /// functionality from users/clients. - /// + /// /// Default: true. /// public bool IsEnabled { get; set; } @@ -64,8 +64,8 @@ namespace Volo.Abp.Authorization.Permissions /// /// Name of the property /// - /// Returns the value in the dictionary by given . - /// Returns null if given is not present in the dictionary. + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. /// public object this[string name] { @@ -74,7 +74,7 @@ namespace Volo.Abp.Authorization.Permissions } protected internal PermissionDefinition( - [NotNull] string name, + [NotNull] string name, ILocalizableString displayName = null, MultiTenancySides multiTenancySide = MultiTenancySides.Both, bool isEnabled = true) @@ -90,14 +90,14 @@ namespace Volo.Abp.Authorization.Permissions } public virtual PermissionDefinition AddChild( - [NotNull] string name, + [NotNull] string name, ILocalizableString displayName = null, MultiTenancySides multiTenancySide = MultiTenancySides.Both, bool isEnabled = true) { var child = new PermissionDefinition( - name, - displayName, + name, + displayName, multiTenancySide, isEnabled) { @@ -138,4 +138,4 @@ namespace Volo.Abp.Authorization.Permissions return $"[{nameof(PermissionDefinition)} {Name}]"; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs index 5038e8e064..6d3a937a94 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs @@ -36,8 +36,8 @@ namespace Volo.Abp.Authorization.Permissions /// /// Name of the property /// - /// Returns the value in the dictionary by given . - /// Returns null if given is not present in the dictionary. + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. /// public object this[string name] { @@ -46,7 +46,7 @@ namespace Volo.Abp.Authorization.Permissions } protected internal PermissionGroupDefinition( - string name, + string name, ILocalizableString displayName = null, MultiTenancySides multiTenancySide = MultiTenancySides.Both) { @@ -59,7 +59,7 @@ namespace Volo.Abp.Authorization.Permissions } public virtual PermissionDefinition AddPermission( - string name, + string name, ILocalizableString displayName = null, MultiTenancySides multiTenancySide = MultiTenancySides.Both, bool isEnabled = true) @@ -131,4 +131,4 @@ namespace Volo.Abp.Authorization.Permissions return null; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs index 262d95d35b..18f38128db 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs @@ -8,9 +8,9 @@ namespace Volo.Abp.BackgroundJobs public interface IAsyncBackgroundJob { /// - /// Executes the job with the . + /// Executes the job with the . /// /// Job arguments. Task ExecuteAsync(TArgs args); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs index e7c942ec4c..94b75f4c91 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs @@ -6,9 +6,9 @@ public interface IBackgroundJob { /// - /// Executes the job with the . + /// Executes the job with the . /// /// Job arguments. void Execute(TArgs args); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactoryExtensions.cs b/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactoryExtensions.cs index 1dc51a2a72..e2d5ff25e9 100644 --- a/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactoryExtensions.cs +++ b/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactoryExtensions.cs @@ -6,7 +6,6 @@ /// Gets a named container. /// /// The blob container manager - /// Cancellation token /// /// The container object. /// @@ -19,4 +18,4 @@ ); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs index 76ae06a5e0..f272484611 100644 --- a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs @@ -88,7 +88,7 @@ namespace System /// Gets index of nth occurrence of a char in a string. /// /// source string to be searched - /// Char to search in + /// Char to search in /// Count of the occurrence public static int NthIndexOf(this string str, char c, int n) { diff --git a/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpCollectionExtensions.cs b/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpCollectionExtensions.cs index e014ee9e21..f55bdd3bc8 100644 --- a/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpCollectionExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpCollectionExtensions.cs @@ -107,7 +107,7 @@ namespace System.Collections.Generic } /// - /// Removes all items from the collection those satisfy the given . + /// Removes all items from the collection. /// /// Type of the items in the collection /// The collection diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeFinder.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeFinder.cs index 6576f08318..71ea895fd2 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeFinder.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeFinder.cs @@ -37,7 +37,7 @@ namespace Volo.Abp.Reflection allTypes.AddRange(typesInThisAssembly.Where(type => type != null)); } - catch (Exception ex) + catch { //TODO: Trigger a global event? } @@ -46,4 +46,4 @@ namespace Volo.Abp.Reflection return allTypes; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Text/Formatting/FormattedStringValueExtracter.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Text/Formatting/FormattedStringValueExtracter.cs index 6d21fc2a73..00d25681e4 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Text/Formatting/FormattedStringValueExtracter.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Text/Formatting/FormattedStringValueExtracter.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.Text.Formatting /// /// /// Say that str is "My name is Neo." and format is "My name is {name}.". - /// Then Extract method gets "Neo" as "name". + /// Then Extract method gets "Neo" as "name". /// public class FormattedStringValueExtracter { @@ -84,7 +84,7 @@ namespace Volo.Abp.Text.Formatting } /// - /// Checks if given fits to given . + /// Checks if given fits to given . /// Also gets extracted values. /// /// String including dynamic values @@ -127,4 +127,4 @@ namespace Volo.Abp.Text.Formatting } } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContext.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContext.cs index 6cda2f6e39..6c470312d8 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContext.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContext.cs @@ -13,8 +13,8 @@ namespace Volo.Abp.Data /// /// Name of the property /// - /// Returns the value in the dictionary by given . - /// Returns null if given is not present in the dictionary. + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. /// [CanBeNull] public object this[string name] @@ -45,4 +45,4 @@ namespace Volo.Abp.Data return this; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/IAbpCommonDbContextRegistrationOptionsBuilder.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/IAbpCommonDbContextRegistrationOptionsBuilder.cs index 368fa2dc96..53d2f142cd 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/IAbpCommonDbContextRegistrationOptionsBuilder.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/IAbpCommonDbContextRegistrationOptionsBuilder.cs @@ -9,11 +9,11 @@ namespace Volo.Abp.DependencyInjection IServiceCollection Services { get; } /// - /// Registers default repositories for this DbContext. + /// Registers default repositories for this DbContext. /// /// /// Registers repositories only for aggregate root entities by default. - /// set to true to include all entities. + /// set to true to include all entities. /// IAbpCommonDbContextRegistrationOptionsBuilder AddDefaultRepositories(bool includeAllEntities = false); @@ -67,4 +67,4 @@ namespace Volo.Abp.DependencyInjection /// The DbContext type to be replaced IAbpCommonDbContextRegistrationOptionsBuilder ReplaceDbContext(Type otherDbContextType); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs index 1d93c05580..d28b3ab2a4 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs @@ -33,7 +33,7 @@ namespace Volo.Abp.EventBus /// /// Registers to an event. - /// A new instance of object is created for every event occurrence. + /// A new instance of object is created for every event occurrence. /// /// Event type /// Type of the event handler @@ -116,4 +116,4 @@ namespace Volo.Abp.EventBus /// Event type void UnsubscribeAll(Type eventType); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventDataMayHaveTenantId.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventDataMayHaveTenantId.cs index 72a8c753cd..9ff8b89cd8 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventDataMayHaveTenantId.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventDataMayHaveTenantId.cs @@ -16,8 +16,8 @@ namespace Volo.Abp.EventBus { /// /// Returns true if this event data has a Tenant Id information. - /// If so, it should set the our parameter. - /// Otherwise, the our parameter value should not be informative + /// If so, it should set the our parameter. + /// Otherwise, the our parameter value should not be informative /// (it will be null as expected, but doesn't indicate a tenant with null tenant id). /// /// diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs index b2b11f0a18..609f42acd2 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs @@ -69,8 +69,8 @@ namespace Volo.Abp.Features /// /// Name of the property /// - /// Returns the value in the dictionary by given . - /// Returns null if given is not present in the dictionary. + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. /// [CanBeNull] public object this[string name] diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs index cba38070a7..b4dd98eb5b 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs @@ -29,8 +29,8 @@ namespace Volo.Abp.Features /// /// Name of the property /// - /// Returns the value in the dictionary by given . - /// Returns null if given is not present in the dictionary. + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. /// public object this[string name] { @@ -39,7 +39,7 @@ namespace Volo.Abp.Features } protected internal FeatureGroupDefinition( - string name, + string name, ILocalizableString displayName = null) { Name = name; @@ -108,4 +108,4 @@ namespace Volo.Abp.Features return $"[{nameof(FeatureGroupDefinition)} {Name}]"; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkFailedEventArgs.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkFailedEventArgs.cs index df867c2320..ed225ccc58 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkFailedEventArgs.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkFailedEventArgs.cs @@ -9,8 +9,8 @@ namespace Volo.Abp.Uow public class UnitOfWorkFailedEventArgs : UnitOfWorkEventArgs { /// - /// Exception that caused failure. This is set only if an error occurred during . - /// Can be null if there is no exception, but is not called. + /// Exception that caused failure. This is set only if an error occurred during . + /// Can be null if there is no exception, but is not called. /// Can be null if another exception occurred during the UOW. /// [CanBeNull] diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Basic_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Basic_Tests.cs index 3ac2246dcc..ea70649350 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Basic_Tests.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Basic_Tests.cs @@ -38,12 +38,12 @@ namespace Volo.Abp.AutoMapper } //[Fact] TODO: Disabled because of https://github.com/AutoMapper/AutoMapper/pull/2379#issuecomment-355899664 - public void Should_Not_Map_Objects_With_AutoMap_Attributes() + /*public void Should_Not_Map_Objects_With_AutoMap_Attributes() { Assert.ThrowsAny(() => { _objectMapper.Map(new MyEntity {Number = 42}); }); - } + }*/ } } diff --git a/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs b/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs index bf120d2e33..8fd3d68b18 100644 --- a/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs +++ b/framework/test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs @@ -26,7 +26,7 @@ namespace Volo.Abp.Uow { uow.OnCompleted(() => { - completed = true; + completed = true; return Task.CompletedTask; }); @@ -50,7 +50,12 @@ namespace Volo.Abp.Uow { using (var childUow = _unitOfWorkManager.Begin()) { - childUow.OnCompleted(async () => completed = true); + childUow.OnCompleted(() => + { + completed = true; + return Task.CompletedTask; + }); + uow.Disposed += (sender, args) => disposed = true; await childUow.CompleteAsync(); @@ -80,9 +85,14 @@ namespace Volo.Abp.Uow using (var uow = _unitOfWorkManager.Begin()) { - uow.OnCompleted(async () => completed = true); - uow.Failed += (sender, args) => failed = true; - uow.Disposed += (sender, args) => disposed = true; + uow.OnCompleted(() => + { + completed = true; + return Task.CompletedTask; + }); + + uow.Failed += (_, _) => failed = true; + uow.Disposed += (_, _) => disposed = true; } completed.ShouldBeFalse(); @@ -101,7 +111,12 @@ namespace Volo.Abp.Uow { using (var uow = _unitOfWorkManager.Begin()) { - uow.OnCompleted(async () => completed = true); + uow.OnCompleted(() => + { + completed = true; + return Task.CompletedTask; + }); + uow.Failed += (sender, args) => failed = true; uow.Disposed += (sender, args) => disposed = true; @@ -125,7 +140,12 @@ namespace Volo.Abp.Uow using (var uow = _unitOfWorkManager.Begin()) { - uow.OnCompleted(async () => completed = true); + uow.OnCompleted(() => + { + completed = true; + return Task.CompletedTask; + }); + uow.Failed += (sender, args) => { failed = true; args.IsRolledback.ShouldBeTrue(); }; uow.Disposed += (sender, args) => disposed = true; From 8f3c527126e6c5e89bf9c96a65910807bac8f6bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 20:14:13 +0300 Subject: [PATCH 13/83] Use async methods in the mongo repo. --- .../Repositories/MongoDB/MongoDbRepository.cs | 86 +++++++++++-------- .../MongoDbCoreRepositoryExtensions.cs | 24 +++++- 2 files changed, 74 insertions(+), 36 deletions(-) diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 52b78eb7a3..ab0c063191 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -114,28 +114,33 @@ namespace Volo.Abp.Domain.Repositories.MongoDB public override async Task InsertManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { - foreach (var entity in entities) + var entityArray = entities.ToArray(); + + foreach (var entity in entityArray) { await ApplyAbpConceptsForAddedEntityAsync(entity); } + var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken)); + var collection = dbContext.Collection(); + if (BulkOperationProvider != null) { - await BulkOperationProvider.InsertManyAsync(this, entities, SessionHandle, autoSave, cancellationToken); + await BulkOperationProvider.InsertManyAsync(this, entityArray, dbContext.SessionHandle, autoSave, cancellationToken); return; } - if (SessionHandle != null) + if (dbContext.SessionHandle != null) { - await Collection.InsertManyAsync( - SessionHandle, - entities, + await collection.InsertManyAsync( + dbContext.SessionHandle, + entityArray, cancellationToken: cancellationToken); } else { - await Collection.InsertManyAsync( - entities, + await collection.InsertManyAsync( + entityArray, cancellationToken: cancellationToken); } } @@ -193,12 +198,13 @@ namespace Volo.Abp.Domain.Repositories.MongoDB public override async Task UpdateManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { - var isSoftDeleteEntity = typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)); + var entityArray = entities.ToArray(); - foreach (var entity in entities) + foreach (var entity in entityArray) { SetModificationAuditProperties(entity); + var isSoftDeleteEntity = typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)); if (isSoftDeleteEntity) { SetDeletionAuditProperties(entity); @@ -214,31 +220,34 @@ namespace Volo.Abp.Domain.Repositories.MongoDB SetNewConcurrencyStamp(entity); } + cancellationToken = GetCancellationToken(cancellationToken); + var dbContext = await GetDbContextAsync(cancellationToken); + if (BulkOperationProvider != null) { - await BulkOperationProvider.UpdateManyAsync(this, entities, SessionHandle, autoSave, cancellationToken); + await BulkOperationProvider.UpdateManyAsync(this, entityArray, dbContext.SessionHandle, autoSave, cancellationToken); return; } - var entitiesCount = entities.Count(); BulkWriteResult result; List> replaceRequests = new List>(); - foreach (var entity in entities) + foreach (var entity in entityArray) { replaceRequests.Add(new ReplaceOneModel(CreateEntityFilter(entity), entity)); } - if (SessionHandle != null) + var collection = dbContext.Collection(); + if (dbContext.SessionHandle != null) { - result = await Collection.BulkWriteAsync(SessionHandle, replaceRequests); + result = await collection.BulkWriteAsync(dbContext.SessionHandle, replaceRequests, cancellationToken: cancellationToken); } else { - result = await Collection.BulkWriteAsync(replaceRequests); + result = await collection.BulkWriteAsync(replaceRequests, cancellationToken: cancellationToken); } - if (result.MatchedCount < entitiesCount) + if (result.MatchedCount < entityArray.Length) { ThrowOptimisticConcurrencyException(); } @@ -315,35 +324,40 @@ namespace Volo.Abp.Domain.Repositories.MongoDB bool autoSave = false, CancellationToken cancellationToken = default) { - foreach (var entity in entities) + var entityArray = entities.ToArray(); + + foreach (var entity in entityArray) { await ApplyAbpConceptsForDeletedEntityAsync(entity); - var oldConcurrencyStamp = SetNewConcurrencyStamp(entity); + SetNewConcurrencyStamp(entity); } + var dbContext = await GetDbContextAsync(GetCancellationToken(cancellationToken)); + var collection = dbContext.Collection(); + if (BulkOperationProvider != null) { - await BulkOperationProvider.DeleteManyAsync(this, entities, SessionHandle, autoSave, cancellationToken); + await BulkOperationProvider.DeleteManyAsync(this, entityArray, dbContext.SessionHandle, autoSave, cancellationToken); return; } - var entitiesCount = entities.Count(); + var entitiesCount = entityArray.Count(); if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) { UpdateResult updateResult; - if (SessionHandle != null) + if (dbContext.SessionHandle != null) { - updateResult = await Collection.UpdateManyAsync( - SessionHandle, - CreateEntitiesFilter(entities), + updateResult = await collection.UpdateManyAsync( + dbContext.SessionHandle, + CreateEntitiesFilter(entityArray), Builders.Update.Set(x => ((ISoftDelete)x).IsDeleted, true) ); } else { - updateResult = await Collection.UpdateManyAsync( - CreateEntitiesFilter(entities), + updateResult = await collection.UpdateManyAsync( + CreateEntitiesFilter(entityArray), Builders.Update.Set(x => ((ISoftDelete)x).IsDeleted, true) ); } @@ -356,17 +370,17 @@ namespace Volo.Abp.Domain.Repositories.MongoDB else { DeleteResult deleteResult; - if (SessionHandle != null) + if (dbContext.SessionHandle != null) { - deleteResult = await Collection.DeleteManyAsync( - SessionHandle, - CreateEntitiesFilter(entities) + deleteResult = await collection.DeleteManyAsync( + dbContext.SessionHandle, + CreateEntitiesFilter(entityArray) ); } else { - deleteResult = await Collection.DeleteManyAsync( - CreateEntitiesFilter(entities) + deleteResult = await collection.DeleteManyAsync( + CreateEntitiesFilter(entityArray) ); } @@ -689,9 +703,11 @@ namespace Volo.Abp.Domain.Repositories.MongoDB public virtual async Task DeleteManyAsync([NotNull] IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) { - var entities = await GetMongoQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + + var entities = await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => ids.Contains(x.Id)) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(cancellationToken); await DeleteManyAsync(entities, autoSave, cancellationToken); } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs index 12da0afaa2..ff367dc554 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; using Volo.Abp.Domain.Entities; @@ -8,24 +9,45 @@ namespace Volo.Abp.Domain.Repositories { public static class MongoDbCoreRepositoryExtensions { + [Obsolete("Use GetDatabaseAsync method.")] public static IMongoDatabase GetDatabase(this IBasicRepository repository) where TEntity : class, IEntity { return repository.ToMongoDbRepository().Database; } + public static Task GetDatabaseAsync(this IBasicRepository repository) + where TEntity : class, IEntity + { + return repository.ToMongoDbRepository().GetDatabaseAsync(); + } + + [Obsolete("Use GetCollection method.")] public static IMongoCollection GetCollection(this IBasicRepository repository) where TEntity : class, IEntity { return repository.ToMongoDbRepository().Collection; } + public static Task> GetCollectionAsync(this IBasicRepository repository) + where TEntity : class, IEntity + { + return repository.ToMongoDbRepository().GetCollectionAsync(); + } + + [Obsolete("Use GetMongoQueryableAsync method.")] public static IMongoQueryable GetMongoQueryable(this IBasicRepository repository) where TEntity : class, IEntity { return repository.ToMongoDbRepository().GetMongoQueryable(); } + public static Task> GetMongoQueryableAsync(this IBasicRepository repository) + where TEntity : class, IEntity + { + return repository.ToMongoDbRepository().GetMongoQueryableAsync(); + } + public static IMongoDbRepository ToMongoDbRepository(this IBasicRepository repository) where TEntity : class, IEntity { @@ -38,4 +60,4 @@ namespace Volo.Abp.Domain.Repositories return mongoDbRepository; } } -} \ No newline at end of file +} From ac652f2a1f03e09c59d24a740c3a00675cd585e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 20:20:12 +0300 Subject: [PATCH 14/83] Fix sync usages. --- .../Abp/Application/Services/ReadOnlyAppService.cs | 4 ++-- .../Abp/TestApp/EntityFrameworkCore/CityRepository.cs | 4 ++-- .../TestApp/EntityFrameworkCore/PersonRepository.cs | 4 ++-- .../MongoDbAsyncQueryableProvider_Tests.cs | 4 ++-- .../Volo/Abp/TestApp/MongoDb/CityRepository.cs | 4 ++-- .../Abp/TestApp/Testing/Repository_Queryable_Tests.cs | 10 ++++------ 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs index c585b2ac38..da3f386fd9 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ReadOnlyAppService.cs @@ -38,7 +38,7 @@ namespace Volo.Abp.Application.Services where TGetOutputDto : IEntityDto where TGetListOutputDto : IEntityDto { - protected new IReadOnlyRepository Repository { get; } + protected IReadOnlyRepository Repository { get; } protected ReadOnlyAppService(IReadOnlyRepository repository) : base(repository) @@ -46,7 +46,7 @@ namespace Volo.Abp.Application.Services Repository = repository; } - protected async override Task GetEntityByIdAsync(TKey id) + protected override async Task GetEntityByIdAsync(TKey id) { return await Repository.GetAsync(id); } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/CityRepository.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/CityRepository.cs index 027f54a03a..cd85cbcb5a 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/CityRepository.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/CityRepository.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore { public class CityRepository : EfCoreRepository, ICityRepository { - public CityRepository(IDbContextProvider dbContextProvider) + public CityRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) { } @@ -24,7 +24,7 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore public async Task> GetPeopleInTheCityAsync(string cityName) { var city = await FindByNameAsync(cityName); - return await DbContext.People.Where(p => p.CityId == city.Id).ToListAsync(); + return await (await GetDbContextAsync()).People.Where(p => p.CityId == city.Id).ToListAsync(); } } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs index ab8c1920a7..6413140bf1 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore public async Task GetViewAsync(string name) { - return await DbContext.PersonView.Where(x => x.Name == name).FirstOrDefaultAsync(); + return await (await GetDbContextAsync()).PersonView.Where(x => x.Name == name).FirstOrDefaultAsync(); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/MongoDbAsyncQueryableProvider_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/MongoDbAsyncQueryableProvider_Tests.cs index ae9be03d57..5335aa11be 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/MongoDbAsyncQueryableProvider_Tests.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/MongoDbAsyncQueryableProvider_Tests.cs @@ -25,10 +25,10 @@ namespace Volo.Abp.MongoDB.Repositories } [Fact] - public void CanExecute() + public async Task CanExecuteAsync() { _mongoDbAsyncQueryableProvider.CanExecute(_personRepository).ShouldBeTrue(); - _mongoDbAsyncQueryableProvider.CanExecute(_personRepository.WithDetails()).ShouldBeTrue(); + _mongoDbAsyncQueryableProvider.CanExecute(await _personRepository.WithDetailsAsync()).ShouldBeTrue(); } [Fact] diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs index bb31883010..df6eed85cc 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/CityRepository.cs @@ -19,13 +19,13 @@ namespace Volo.Abp.TestApp.MongoDB public async Task FindByNameAsync(string name) { - return await (await Collection.FindAsync(c => c.Name == name)).FirstOrDefaultAsync(); + return await (await (await GetCollectionAsync()).FindAsync(c => c.Name == name)).FirstOrDefaultAsync(); } public async Task> GetPeopleInTheCityAsync(string cityName) { var city = await FindByNameAsync(cityName); - return await DbContext.People.AsQueryable().Where(p => p.CityId == city.Id).ToListAsync(); + return await (await GetDbContextAsync()).People.AsQueryable().Where(p => p.CityId == city.Id).ToListAsync(); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Queryable_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Queryable_Tests.cs index 6078236380..3ca511a7ea 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Queryable_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Queryable_Tests.cs @@ -44,24 +44,22 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task WithDetails() { - await WithUnitOfWorkAsync(() => + await WithUnitOfWorkAsync(async () => { - var person = PersonRepository.WithDetails().Single(p => p.Id == TestDataBuilder.UserDouglasId); + var person = (await PersonRepository.WithDetailsAsync()).Single(p => p.Id == TestDataBuilder.UserDouglasId); person.Name.ShouldBe("Douglas"); person.Phones.Count.ShouldBe(2); - return Task.CompletedTask; }); } [Fact] public async Task WithDetails_Explicit() { - await WithUnitOfWorkAsync(() => + await WithUnitOfWorkAsync(async () => { - var person = PersonRepository.WithDetails(p => p.Phones).Single(p => p.Id == TestDataBuilder.UserDouglasId); + var person = (await PersonRepository.WithDetailsAsync(p => p.Phones)).Single(p => p.Id == TestDataBuilder.UserDouglasId); person.Name.ShouldBe("Douglas"); person.Phones.Count.ShouldBe(2); - return Task.CompletedTask; }); } } From d57c468e09178dfd8f305a97f570f58d68e527ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 20:25:27 +0300 Subject: [PATCH 15/83] fix summaries. --- .../TagHelpers/Pagination/PagerModel.cs | 2 +- framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs | 4 ++-- .../Application/Services/AbstractKeyCrudAppService.cs | 10 +++++----- .../Services/AbstractKeyReadOnlyAppService.cs | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/PagerModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/PagerModel.cs index 980aacee8a..3c4eb1b88e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/PagerModel.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/PagerModel.cs @@ -69,7 +69,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination } /// - /// Gets first two, previous & current & next, last two pages + /// Gets first two, previous, current, next, last two pages /// private List GetPagesWithGaps() { diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs index 612034af19..9a820600bd 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs @@ -439,10 +439,10 @@ namespace Volo.Abp.BlazoriseUI } /// - /// Calls IAuthorizationService.CheckAsync for the given . + /// Calls IAuthorizationService.CheckAsync for the given . /// Throws if given policy was not granted for the current user. /// - /// Does nothing if is null or empty. + /// Does nothing if is null or empty. /// /// A policy name to check protected virtual async Task CheckPolicyAsync([CanBeNull] string policyName) diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs index 91879f030e..ea0ca508d5 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs @@ -132,7 +132,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to to create a new entity. + /// Maps to to create a new entity. /// It uses by default. /// It can be overriden for custom mapping. /// Overriding this has higher priority than overriding the @@ -143,7 +143,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to to create a new entity. + /// Maps to to create a new entity. /// It uses by default. /// It can be overriden for custom mapping. /// @@ -155,7 +155,7 @@ namespace Volo.Abp.Application.Services } /// - /// Sets Id value for the entity if is . + /// Sets Id value for the entity if is . /// It's used while creating a new entity. /// protected virtual void SetIdForGuids(TEntity entity) @@ -171,7 +171,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to to update the entity. + /// Maps to to update the entity. /// It uses by default. /// It can be overriden for custom mapping. /// Overriding this has higher priority than overriding the @@ -183,7 +183,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to to update the entity. + /// Maps to to update the entity. /// It uses by default. /// It can be overriden for custom mapping. /// diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs index b9ffe3359b..54c6bd7918 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs @@ -166,7 +166,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to . + /// Maps to . /// It internally calls the by default. /// It can be overriden for custom mapping. /// Overriding this has higher priority than overriding the @@ -177,7 +177,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to . + /// Maps to . /// It uses by default. /// It can be overriden for custom mapping. /// @@ -187,7 +187,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps a list of to objects. + /// Maps a list of to objects. /// It uses method for each item in the list. /// protected virtual async Task> MapToGetListOutputDtosAsync(List entities) @@ -203,7 +203,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to . + /// Maps to . /// It internally calls the by default. /// It can be overriden for custom mapping. /// Overriding this has higher priority than overriding the @@ -214,7 +214,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to . + /// Maps to . /// It uses by default. /// It can be overriden for custom mapping. /// From b28553706156f16efe338de0e46e368faa04d7dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 20:36:37 +0300 Subject: [PATCH 16/83] Fix typeparamref. --- .../Application/Services/AbstractKeyCrudAppService.cs | 10 +++++----- .../Services/AbstractKeyReadOnlyAppService.cs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs index ea0ca508d5..0cfb8ceb24 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyCrudAppService.cs @@ -132,7 +132,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to to create a new entity. + /// Maps to to create a new entity. /// It uses by default. /// It can be overriden for custom mapping. /// Overriding this has higher priority than overriding the @@ -143,7 +143,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to to create a new entity. + /// Maps to to create a new entity. /// It uses by default. /// It can be overriden for custom mapping. /// @@ -155,7 +155,7 @@ namespace Volo.Abp.Application.Services } /// - /// Sets Id value for the entity if is . + /// Sets Id value for the entity if is . /// It's used while creating a new entity. /// protected virtual void SetIdForGuids(TEntity entity) @@ -171,7 +171,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to to update the entity. + /// Maps to to update the entity. /// It uses by default. /// It can be overriden for custom mapping. /// Overriding this has higher priority than overriding the @@ -183,7 +183,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to to update the entity. + /// Maps to to update the entity. /// It uses by default. /// It can be overriden for custom mapping. /// diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs index 54c6bd7918..b2e11678f8 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs @@ -166,7 +166,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to . + /// Maps to . /// It internally calls the by default. /// It can be overriden for custom mapping. /// Overriding this has higher priority than overriding the @@ -177,7 +177,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to . + /// Maps to . /// It uses by default. /// It can be overriden for custom mapping. /// @@ -187,7 +187,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps a list of to objects. + /// Maps a list of to objects. /// It uses method for each item in the list. /// protected virtual async Task> MapToGetListOutputDtosAsync(List entities) @@ -203,7 +203,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to . + /// Maps to . /// It internally calls the by default. /// It can be overriden for custom mapping. /// Overriding this has higher priority than overriding the @@ -214,7 +214,7 @@ namespace Volo.Abp.Application.Services } /// - /// Maps to . + /// Maps to . /// It uses by default. /// It can be overriden for custom mapping. /// From e5df75c7706f0cb04bdce3786d908b1393445afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 20:53:01 +0300 Subject: [PATCH 17/83] Use async methods for audit logging module. --- .../EfCoreAuditLogRepository.cs | 52 +++++++++++-------- .../MongoDB/MongoAuditLogRepository.cs | 25 +++++---- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs index 6677f2d4a2..edb1f3f599 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs @@ -39,7 +39,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = GetListQuery( + var query = await GetListQueryAsync( startTime, endTime, httpMethod, @@ -75,7 +75,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore HttpStatusCode? httpStatusCode = null, CancellationToken cancellationToken = default) { - var query = GetListQuery( + var query = await GetListQueryAsync( startTime, endTime, httpMethod, @@ -94,7 +94,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore return totalCount; } - protected virtual IQueryable GetListQuery( + protected virtual async Task> GetListQueryAsync( DateTime? startTime = null, DateTime? endTime = null, string httpMethod = null, @@ -109,7 +109,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore bool includeDetails = false) { var nHttpStatusCode = (int?) httpStatusCode; - return DbSet.AsNoTracking() + return (await GetDbSetAsync()).AsNoTracking() .IncludeDetails(includeDetails) .WhereIf(startTime.HasValue, auditLog => auditLog.ExecutionTime >= startTime) .WhereIf(endTime.HasValue, auditLog => auditLog.ExecutionTime <= endTime) @@ -127,7 +127,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore public virtual async Task> GetAverageExecutionDurationPerDayAsync(DateTime startDate, DateTime endDate) { - var result = await DbSet.AsNoTracking() + var result = await (await GetDbSetAsync()).AsNoTracking() .Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate) .OrderBy(t => t.ExecutionTime) .GroupBy(t => new { t.ExecutionTime.Date }) @@ -137,14 +137,20 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore return result.ToDictionary(element => element.Day.ClearTime(), element => element.avgExecutionTime); } + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } + public virtual async Task GetEntityChange(Guid entityChangeId) { - var entityChange = await DbContext.Set() + var entityChange = await (await GetDbContextAsync()).Set() .AsNoTracking() .IncludeDetails() .Where(x => x.Id == entityChangeId) @@ -172,7 +178,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = GetEntityChangeListQuery(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName, includeDetails); + var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName, includeDetails); return await query.OrderBy(sorting ?? "changeTime desc") .PageBy(skipCount, maxResultCount) @@ -188,7 +194,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore string entityTypeFullName = null, CancellationToken cancellationToken = default) { - var query = GetEntityChangeListQuery(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName); + var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName); var totalCount = await query.LongCountAsync(GetCancellationToken(cancellationToken)); @@ -197,7 +203,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore public virtual async Task GetEntityChangeWithUsernameAsync(Guid entityChangeId) { - var auditLog = await DbSet.AsNoTracking().IncludeDetails() + var auditLog = await (await GetDbSetAsync()).AsNoTracking().IncludeDetails() .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)).FirstAsync(); return new EntityChangeWithUsername() @@ -209,18 +215,20 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore public virtual async Task> GetEntityChangesWithUsernameAsync(string entityId, string entityTypeFullName) { - var query = DbContext.Set() + var dbContext = await GetDbContextAsync(); + + var query = dbContext.Set() .AsNoTracking() .IncludeDetails() .Where(x => x.EntityId == entityId && x.EntityTypeFullName == entityTypeFullName); return await (from e in query - join auditLog in DbSet on e.AuditLogId equals auditLog.Id - select new EntityChangeWithUsername() {EntityChange = e, UserName = auditLog.UserName}) + join auditLog in dbContext.AuditLogs on e.AuditLogId equals auditLog.Id + select new EntityChangeWithUsername {EntityChange = e, UserName = auditLog.UserName}) .OrderByDescending(x => x.EntityChange.ChangeTime).ToListAsync(); } - protected virtual IQueryable GetEntityChangeListQuery( + protected virtual async Task> GetEntityChangeListQueryAsync( Guid? auditLogId = null, DateTime? startTime = null, DateTime? endTime = null, @@ -229,14 +237,16 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore string entityTypeFullName = null, bool includeDetails = false) { - return DbContext.Set().AsNoTracking().IncludeDetails(includeDetails) - .WhereIf(auditLogId.HasValue, e => e.AuditLogId == auditLogId) - .WhereIf(startTime.HasValue, e => e.ChangeTime >= startTime) - .WhereIf(endTime.HasValue, e => e.ChangeTime <= endTime) - .WhereIf(changeType.HasValue, e => e.ChangeType == changeType) - .WhereIf(!string.IsNullOrWhiteSpace(entityId), e => e.EntityId == entityId) - .WhereIf(!string.IsNullOrWhiteSpace(entityTypeFullName), - e => e.EntityTypeFullName.Contains(entityTypeFullName)); + return (await GetDbContextAsync()) + .Set() + .AsNoTracking() + .IncludeDetails(includeDetails) + .WhereIf(auditLogId.HasValue, e => e.AuditLogId == auditLogId) + .WhereIf(startTime.HasValue, e => e.ChangeTime >= startTime) + .WhereIf(endTime.HasValue, e => e.ChangeTime <= endTime) + .WhereIf(changeType.HasValue, e => e.ChangeType == changeType) + .WhereIf(!string.IsNullOrWhiteSpace(entityId), e => e.EntityId == entityId) + .WhereIf(!string.IsNullOrWhiteSpace(entityTypeFullName), e => e.EntityTypeFullName.Contains(entityTypeFullName)); } } } diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs index 14e4dd39c7..95981d6355 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs @@ -40,7 +40,7 @@ namespace Volo.Abp.AuditLogging.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = GetListQuery( + var query = await GetListQueryAsync( startTime, endTime, httpMethod, @@ -74,7 +74,7 @@ namespace Volo.Abp.AuditLogging.MongoDB HttpStatusCode? httpStatusCode = null, CancellationToken cancellationToken = default) { - var query = GetListQuery( + var query = await GetListQueryAsync( startTime, endTime, httpMethod, @@ -94,7 +94,7 @@ namespace Volo.Abp.AuditLogging.MongoDB return count; } - protected virtual IQueryable GetListQuery( + protected virtual async Task> GetListQueryAsync( DateTime? startTime = null, DateTime? endTime = null, string httpMethod = null, @@ -108,7 +108,7 @@ namespace Volo.Abp.AuditLogging.MongoDB HttpStatusCode? httpStatusCode = null, bool includeDetails = false) { - return GetMongoQueryable() + return (await GetMongoQueryableAsync()) .WhereIf(startTime.HasValue, auditLog => auditLog.ExecutionTime >= startTime) .WhereIf(endTime.HasValue, auditLog => auditLog.ExecutionTime <= endTime) .WhereIf(hasException.HasValue && hasException.Value, auditLog => auditLog.Exceptions != null && auditLog.Exceptions != "") @@ -126,7 +126,7 @@ namespace Volo.Abp.AuditLogging.MongoDB public virtual async Task> GetAverageExecutionDurationPerDayAsync(DateTime startDate, DateTime endDate) { - var result = await GetMongoQueryable() + var result = await (await GetMongoQueryableAsync()) .Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate) .OrderBy(t => t.ExecutionTime) .GroupBy(t => new @@ -143,12 +143,11 @@ namespace Volo.Abp.AuditLogging.MongoDB public virtual async Task GetEntityChange(Guid entityChangeId) { - var entityChange = (await GetMongoQueryable() + var entityChange = (await (await GetMongoQueryableAsync()) .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)) .OrderBy(x => x.Id) .FirstAsync()).EntityChanges.FirstOrDefault(x => x.Id == entityChangeId); - if (entityChange == null) { throw new EntityNotFoundException(typeof(EntityChange)); @@ -170,7 +169,7 @@ namespace Volo.Abp.AuditLogging.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = GetEntityChangeListQuery(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName); + var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName); var auditLogs = await query.As>() .PageBy>(skipCount, maxResultCount) @@ -188,7 +187,7 @@ namespace Volo.Abp.AuditLogging.MongoDB string entityTypeFullName = null, CancellationToken cancellationToken = default) { - var query = GetEntityChangeListQuery(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName); + var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName); var count = await query.As>().LongCountAsync(GetCancellationToken(cancellationToken)); @@ -197,7 +196,7 @@ namespace Volo.Abp.AuditLogging.MongoDB public virtual async Task GetEntityChangeWithUsernameAsync(Guid entityChangeId) { - var auditLog = (await GetMongoQueryable() + var auditLog = (await (await GetMongoQueryableAsync()) .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)) .FirstAsync()); @@ -210,7 +209,7 @@ namespace Volo.Abp.AuditLogging.MongoDB public virtual async Task> GetEntityChangesWithUsernameAsync(string entityId, string entityTypeFullName) { - var auditLogs = await GetMongoQueryable() + var auditLogs = await (await GetMongoQueryableAsync()) .Where(x => x.EntityChanges.Any(y => y.EntityId == entityId && y.EntityTypeFullName == entityTypeFullName)) .As>() .OrderByDescending(x => x.ExecutionTime) @@ -224,7 +223,7 @@ namespace Volo.Abp.AuditLogging.MongoDB {EntityChange = x, UserName = auditLogs.First(y => y.Id == x.AuditLogId).UserName}).ToList(); } - protected virtual IQueryable GetEntityChangeListQuery( + protected virtual async Task> GetEntityChangeListQueryAsync( Guid? auditLogId = null, DateTime? startTime = null, DateTime? endTime = null, @@ -232,7 +231,7 @@ namespace Volo.Abp.AuditLogging.MongoDB string entityId = null, string entityTypeFullName = null) { - return GetMongoQueryable() + return (await GetMongoQueryableAsync()) .SelectMany(x => x.EntityChanges) .WhereIf(auditLogId.HasValue, e => e.Id == auditLogId) .WhereIf(startTime.HasValue, e => e.ChangeTime >= startTime) From 1525246a4dfe4aafe8815b9b6d3b1b15f9fa27a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 20:57:59 +0300 Subject: [PATCH 18/83] Use async in background jobs module. --- .../EfCoreBackgroundJobRepository.cs | 9 ++++----- .../MongoDB/MongoBackgroundJobRepository.cs | 11 +++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs index 29d2bb0170..1971faf380 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/EfCoreBackgroundJobRepository.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore public EfCoreBackgroundJobRepository( IDbContextProvider dbContextProvider, - IClock clock) + IClock clock) : base(dbContextProvider) { Clock = clock; @@ -23,14 +23,13 @@ namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore public virtual async Task> GetWaitingListAsync(int maxResultCount) { - return await GetWaitingListQuery(maxResultCount) - .ToListAsync(); + return await (await GetWaitingListQueryAsync(maxResultCount)).ToListAsync(); } - protected virtual IQueryable GetWaitingListQuery(int maxResultCount) + protected virtual async Task> GetWaitingListQueryAsync(int maxResultCount) { var now = Clock.Now; - return DbSet + return (await GetDbSetAsync()) .Where(t => !t.IsAbandoned && t.NextTryTime <= now) .OrderByDescending(t => t.Priority) .ThenBy(t => t.TryCount) diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs index 4399e15a98..258c9310e2 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/MongoBackgroundJobRepository.cs @@ -14,8 +14,8 @@ namespace Volo.Abp.BackgroundJobs.MongoDB protected IClock Clock { get; } public MongoBackgroundJobRepository( - IMongoDbContextProvider dbContextProvider, - IClock clock) + IMongoDbContextProvider dbContextProvider, + IClock clock) : base(dbContextProvider) { Clock = clock; @@ -23,14 +23,13 @@ namespace Volo.Abp.BackgroundJobs.MongoDB public virtual async Task> GetWaitingListAsync(int maxResultCount) { - return await GetWaitingListQuery(maxResultCount) - .ToListAsync(); + return await (await GetWaitingListQuery(maxResultCount)).ToListAsync(); } - protected virtual IMongoQueryable GetWaitingListQuery(int maxResultCount) + protected virtual async Task> GetWaitingListQuery(int maxResultCount) { var now = Clock.Now; - return GetMongoQueryable() + return (await GetMongoQueryableAsync()) .Where(t => !t.IsAbandoned && t.NextTryTime <= now) .OrderByDescending(t => t.Priority) .ThenBy(t => t.TryCount) From 4d4121a3130ee3bbd463224287e94201611ffc5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 21:06:59 +0300 Subject: [PATCH 19/83] Use async methods in the blob repo. --- .../EfCoreDatabaseBlobContainerRepository.cs | 7 +++-- .../EfCoreDatabaseBlobRepository.cs | 13 ++++---- .../MongoDB/MongoDbDatabaseBlobRepository.cs | 30 +++++++++++-------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/EfCoreDatabaseBlobContainerRepository.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/EfCoreDatabaseBlobContainerRepository.cs index e1d0764807..64b7e3e40a 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/EfCoreDatabaseBlobContainerRepository.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/EfCoreDatabaseBlobContainerRepository.cs @@ -10,14 +10,15 @@ namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore { public class EfCoreDatabaseBlobContainerRepository : EfCoreRepository, IDatabaseBlobContainerRepository { - public EfCoreDatabaseBlobContainerRepository(IDbContextProvider dbContextProvider) + public EfCoreDatabaseBlobContainerRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) { } public virtual async Task FindAsync(string name, CancellationToken cancellationToken = default) { - return await DbSet.FirstOrDefaultAsync(x => x.Name == name, GetCancellationToken(cancellationToken)); + return await (await GetDbSetAsync()) + .FirstOrDefaultAsync(x => x.Name == name, GetCancellationToken(cancellationToken)); } } -} \ No newline at end of file +} diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/EfCoreDatabaseBlobRepository.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/EfCoreDatabaseBlobRepository.cs index 098f6095e4..2ae9331def 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/EfCoreDatabaseBlobRepository.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/EfCoreDatabaseBlobRepository.cs @@ -20,7 +20,8 @@ namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore string name, CancellationToken cancellationToken = default) { - return await DbSet.FirstOrDefaultAsync( + return await (await GetDbSetAsync()) + .FirstOrDefaultAsync( x => x.ContainerId == containerId && x.Name == name, GetCancellationToken(cancellationToken) ); @@ -31,9 +32,11 @@ namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore string name, CancellationToken cancellationToken = default) { - return await DbSet.AnyAsync( - x => x.ContainerId == containerId && x.Name == name, - GetCancellationToken(cancellationToken)); + return await (await GetDbSetAsync()) + .AnyAsync( + x => x.ContainerId == containerId && x.Name == name, + GetCancellationToken(cancellationToken) + ); } public virtual async Task DeleteAsync( @@ -54,4 +57,4 @@ namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore return true; } } -} \ No newline at end of file +} diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/MongoDbDatabaseBlobRepository.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/MongoDbDatabaseBlobRepository.cs index 6c5b034fc1..17945a87db 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/MongoDbDatabaseBlobRepository.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/MongoDbDatabaseBlobRepository.cs @@ -15,35 +15,41 @@ namespace Volo.Abp.BlobStoring.Database.MongoDB public virtual async Task FindAsync(Guid containerId, string name, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().FirstOrDefaultAsync( - x => x.ContainerId == containerId && - x.Name == name, - GetCancellationToken(cancellationToken)); + cancellationToken = GetCancellationToken(cancellationToken); + + return await (await GetMongoQueryableAsync(cancellationToken)) + .FirstOrDefaultAsync( + x => x.ContainerId == containerId && x.Name == name, + cancellationToken + ); } public virtual async Task ExistsAsync(Guid containerId, string name, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().AnyAsync( - x => x.ContainerId == containerId && - x.Name == name, - GetCancellationToken(cancellationToken)); + cancellationToken = GetCancellationToken(cancellationToken); + + return await (await GetMongoQueryableAsync(cancellationToken)) + .AnyAsync( + x => x.ContainerId == containerId && x.Name == name, + cancellationToken + ); } public virtual async Task DeleteAsync( - Guid containerId, + Guid containerId, string name, bool autoSave = false, CancellationToken cancellationToken = default) { var blob = await FindAsync(containerId, name, cancellationToken); - if (blob == null) { return false; } - await base.DeleteAsync(blob, autoSave, cancellationToken: GetCancellationToken(cancellationToken)); + await base.DeleteAsync(blob, autoSave, cancellationToken); + return true; } } -} \ No newline at end of file +} From 7d9013fd511baae36d93212c21a8c4dd9fb028f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 21:09:55 +0300 Subject: [PATCH 20/83] Add missing param --- .../Volo/Abp/Identity/OrganizationUnit.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnit.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnit.cs index 981a0f8fae..53411c1849 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnit.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/OrganizationUnit.cs @@ -49,12 +49,13 @@ namespace Volo.Abp.Identity /// /// Initializes a new instance of the class. /// - /// Tenant's Id or null for host. + /// id /// Display name. /// Parent's Id or null if OU is a root. + /// Tenant's Id or null for host. public OrganizationUnit(Guid id, string displayName, Guid? parentId = null, Guid? tenantId = null) + : base(id) { - Id = id; TenantId = tenantId; DisplayName = displayName; ParentId = parentId; From b1d8411881a362a56e00111667a301c52407da86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 21:21:51 +0300 Subject: [PATCH 21/83] Use async for identity mongodb repos. --- .../MongoIdentityClaimTypeRepository.cs | 8 +-- .../MongoIdentityLinkUserRepository.cs | 4 +- .../MongoDB/MongoIdentityRoleRepository.cs | 12 ++-- .../MongoIdentitySecurityLogRepository.cs | 10 +-- .../MongoDB/MongoIdentityUserRepository.cs | 65 +++++++++++-------- 5 files changed, 57 insertions(+), 42 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityClaimTypeRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityClaimTypeRepository.cs index a123868799..6795735793 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityClaimTypeRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityClaimTypeRepository.cs @@ -24,13 +24,13 @@ namespace Volo.Abp.Identity.MongoDB { if (ignoredId == null) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(ct => ct.Name == name) .AnyAsync(GetCancellationToken(cancellationToken)); } else { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(ct => ct.Id != ignoredId && ct.Name == name) .AnyAsync(GetCancellationToken(cancellationToken)); } @@ -43,7 +43,7 @@ namespace Volo.Abp.Identity.MongoDB string filter, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf>( !filter.IsNullOrWhiteSpace(), u => @@ -59,7 +59,7 @@ namespace Volo.Abp.Identity.MongoDB string filter = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf>( !filter.IsNullOrWhiteSpace(), u => diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityLinkUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityLinkUserRepository.cs index 6e8d53821b..43bad94271 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityLinkUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityLinkUserRepository.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.Identity.MongoDB public async Task FindAsync(IdentityLinkUserInfo sourceLinkUserInfo, IdentityLinkUserInfo targetLinkUserInfo, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .OrderBy(x => x.Id).FirstOrDefaultAsync(x => x.SourceUserId == sourceLinkUserInfo.UserId && x.SourceTenantId == sourceLinkUserInfo.TenantId && x.TargetUserId == targetLinkUserInfo.UserId && x.TargetTenantId == targetLinkUserInfo.TenantId || @@ -30,7 +30,7 @@ namespace Volo.Abp.Identity.MongoDB public async Task> GetListAsync(IdentityLinkUserInfo linkUserInfo, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().Where(x => + return await (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs index 9c6bccf74f..0731008f57 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .OrderBy(x => x.Id) .FirstOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, GetCancellationToken(cancellationToken)); } @@ -36,7 +36,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.NormalizedName.Contains(filter)) @@ -50,7 +50,7 @@ namespace Volo.Abp.Identity.MongoDB IEnumerable ids, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(t => ids.Contains(t.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -59,14 +59,16 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().Where(r => r.IsDefault).ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); + return await (await GetMongoQueryableAsync(cancellationToken)) + .Where(r => r.IsDefault) + .ToListAsync(GetCancellationToken(cancellationToken)); } public async Task GetCountAsync( string filter = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.NormalizedName.Contains(filter)) diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs index b63a6001f9..a0a8b9b103 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs @@ -35,7 +35,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = GetListQuery( + var query = await GetListQueryAsync( startTime, endTime, applicationName, @@ -65,7 +65,7 @@ namespace Volo.Abp.Identity.MongoDB string correlationId = null, CancellationToken cancellationToken = default) { - var query = GetListQuery( + var query = await GetListQueryAsync( startTime, endTime, applicationName, @@ -85,11 +85,11 @@ namespace Volo.Abp.Identity.MongoDB public async Task GetByUserIdAsync(Guid id, Guid userId, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().OrderBy(x => x.Id).FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, + return await (await GetMongoQueryableAsync(cancellationToken)).OrderBy(x => x.Id).FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, GetCancellationToken(cancellationToken)); } - protected virtual IQueryable GetListQuery( + protected virtual async Task> GetListQueryAsync( DateTime? startTime = null, DateTime? endTime = null, string applicationName = null, @@ -100,7 +100,7 @@ namespace Volo.Abp.Identity.MongoDB string clientId = null, string correlationId = null) { - return GetMongoQueryable() + return (await GetMongoQueryableAsync()) .WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime.Value) .WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime < endTime.Value.AddDays(1).Date) .WhereIf(!applicationName.IsNullOrWhiteSpace(), 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 692e5d5016..0864f7b01c 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 @@ -24,7 +24,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .OrderBy(x => x.Id) .FirstOrDefaultAsync( u => u.NormalizedUserName == normalizedUserName, @@ -40,14 +40,17 @@ namespace Volo.Abp.Identity.MongoDB var organizationUnitIds = user.OrganizationUnits .Select(r => r.OrganizationUnitId) .ToArray(); - var organizationUnits = DbContext.OrganizationUnits + + var dbContext = await GetDbContextAsync(cancellationToken); + + var organizationUnits = dbContext.OrganizationUnits .AsQueryable() .Where(ou => organizationUnitIds.Contains(ou.Id)) .ToArray(); var orgUnitRoleIds = organizationUnits.SelectMany(x => x.Roles.Select(r => r.RoleId)).ToArray(); var roleIds = user.Roles.Select(r => r.RoleId).ToArray(); var allRoleIds = orgUnitRoleIds.Union(roleIds); - return await DbContext.Roles.AsQueryable().Where(r => allRoleIds.Contains(r.Id)).Select(r => r.Name).ToListAsync(GetCancellationToken(cancellationToken)); + return await dbContext.Roles.AsQueryable().Where(r => allRoleIds.Contains(r.Id)).Select(r => r.Name).ToListAsync(GetCancellationToken(cancellationToken)); } public async Task> GetRoleNamesInOrganizationUnitAsync( @@ -60,14 +63,16 @@ namespace Volo.Abp.Identity.MongoDB .Select(r => r.OrganizationUnitId) .ToArray(); - var organizationUnits = DbContext.OrganizationUnits + var dbContext = await GetDbContextAsync(cancellationToken); + + var organizationUnits = dbContext.OrganizationUnits .AsQueryable() .Where(ou => organizationUnitIds.Contains(ou.Id)) .ToArray(); var roleIds = organizationUnits.SelectMany(x => x.Roles.Select(r => r.RoleId)).ToArray(); - return await DbContext.Roles //TODO: Such usage suppress filters! + return await dbContext.Roles //TODO: Such usage suppress filters! .AsQueryable() .Where(r => roleIds.Contains(r.Id)) .Select(r => r.Name) @@ -80,7 +85,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(u => u.Logins.Any(login => login.LoginProvider == loginProvider && login.ProviderKey == providerKey)) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -91,7 +96,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .OrderBy(x => x.Id).FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, GetCancellationToken(cancellationToken)); } @@ -100,7 +105,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(u => u.Claims.Any(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value)) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -110,19 +115,21 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - var role = await DbContext.Roles.AsQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + + var role = await (await GetDbContextAsync(cancellationToken)).Roles.AsQueryable() //TODO: Such usages breaks data filters .Where(x => x.NormalizedName == normalizedRoleName) .OrderBy(x => x.Id) - .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + .FirstOrDefaultAsync(cancellationToken); if (role == null) { return new List(); } - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(u => u.Roles.Any(r => r.RoleId == role.Id)) - .ToListAsync(GetCancellationToken(cancellationToken)); + .ToListAsync(cancellationToken); } public virtual async Task> GetListAsync( @@ -133,7 +140,7 @@ namespace Volo.Abp.Identity.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf>( !filter.IsNullOrWhiteSpace(), u => @@ -158,14 +165,17 @@ namespace Volo.Abp.Identity.MongoDB var organizationUnitIds = user.OrganizationUnits .Select(r => r.OrganizationUnitId) .ToArray(); - var organizationUnits = DbContext.OrganizationUnits + + var dbContext = await GetDbContextAsync(cancellationToken); + + var organizationUnits = dbContext.OrganizationUnits .AsQueryable() .Where(ou => organizationUnitIds.Contains(ou.Id)) .ToArray(); var orgUnitRoleIds = organizationUnits.SelectMany(x => x.Roles.Select(r => r.RoleId)).ToArray(); var roleIds = user.Roles.Select(r => r.RoleId).ToArray(); var allRoleIds = orgUnitRoleIds.Union(roleIds); - return await DbContext.Roles.AsQueryable().Where(r => allRoleIds.Contains(r.Id)).ToListAsync(GetCancellationToken(cancellationToken)); + return await dbContext.Roles.AsQueryable().Where(r => allRoleIds.Contains(r.Id)).ToListAsync(GetCancellationToken(cancellationToken)); } public async Task> GetOrganizationUnitsAsync( @@ -175,17 +185,19 @@ namespace Volo.Abp.Identity.MongoDB { var user = await GetAsync(id, cancellationToken: GetCancellationToken(cancellationToken)); var organizationUnitIds = user.OrganizationUnits.Select(r => r.OrganizationUnitId); - return await DbContext.OrganizationUnits.AsQueryable() + + var dbContext = await GetDbContextAsync(cancellationToken); + + return await dbContext.OrganizationUnits.AsQueryable() .Where(ou => organizationUnitIds.Contains(ou.Id)) - .ToListAsync(GetCancellationToken(cancellationToken)) - ; + .ToListAsync(GetCancellationToken(cancellationToken)); } public virtual async Task GetCountAsync( string filter = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf>( !filter.IsNullOrWhiteSpace(), u => @@ -202,7 +214,7 @@ namespace Volo.Abp.Identity.MongoDB Guid organizationUnitId, CancellationToken cancellationToken = default) { - var result = await GetMongoQueryable() + var result = await (await GetMongoQueryableAsync(cancellationToken)) .Where(u => u.OrganizationUnits.Any(uou => uou.OrganizationUnitId == organizationUnitId)) .ToListAsync(GetCancellationToken(cancellationToken)) ; @@ -213,7 +225,7 @@ namespace Volo.Abp.Identity.MongoDB List organizationUnitIds, CancellationToken cancellationToken = default) { - var result = await GetMongoQueryable() + var result = await (await GetMongoQueryableAsync(cancellationToken)) .Where(u => u.OrganizationUnits.Any(uou => organizationUnitIds.Contains(uou.OrganizationUnitId))) .ToListAsync(GetCancellationToken(cancellationToken)) ; @@ -224,16 +236,17 @@ namespace Volo.Abp.Identity.MongoDB string code, CancellationToken cancellationToken = default) { - var organizationUnitIds = await DbContext.OrganizationUnits.AsQueryable() + cancellationToken = GetCancellationToken(cancellationToken); + + var organizationUnitIds = await (await GetDbContextAsync(cancellationToken)).OrganizationUnits.AsQueryable() .Where(ou => ou.Code.StartsWith(code)) .Select(ou => ou.Id) - .ToListAsync(GetCancellationToken(cancellationToken)) + .ToListAsync(cancellationToken) ; - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(u => u.OrganizationUnits.Any(uou => organizationUnitIds.Contains(uou.OrganizationUnitId))) - .ToListAsync(GetCancellationToken(cancellationToken)) - ; + .ToListAsync(cancellationToken); } } } From 1a03098c781deddc1a41400e2182a2382c0e8f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 21:36:22 +0300 Subject: [PATCH 22/83] use async in ids4 repos. --- .../MongoDB/MongoApiResourceRepository.cs | 17 ++++++----------- .../MongoDB/MongoApiScopeRepository.cs | 9 +++++---- .../MongoDB/MongoClientRepository.cs | 14 +++++--------- .../MongoDB/MongoDeviceFlowCodesRepository.cs | 6 +++--- .../MongoDB/MongoIdentityResourceRepository.cs | 14 +++++--------- .../MongoDB/MongoPersistedGrantRepository.cs | 14 +++++++------- 6 files changed, 31 insertions(+), 43 deletions(-) diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs index 599fa913b5..7db1bba8da 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiResourceRepository.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; using Volo.Abp.Domain.Repositories.MongoDB; -using Volo.Abp.IdentityServer.ApiScopes; using System.Linq.Dynamic.Core; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.MongoDB; @@ -21,7 +20,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public async Task FindByNameAsync(string apiResourceName, bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(ar => ar.Name == apiResourceName) .OrderBy(ar => ar.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -30,7 +29,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public async Task> FindByNameAsync(string[] apiResourceNames, bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(ar => apiResourceNames.Contains(ar.Name)) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -38,7 +37,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task> GetListByScopesAsync(string[] scopeNames, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(ar => ar.Scopes.Any(x => scopeNames.Contains(x.Scope))) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -46,7 +45,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task> GetListAsync(string sorting, int skipCount, int maxResultCount, string filter, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.Description.Contains(filter) || @@ -57,14 +56,10 @@ namespace Volo.Abp.IdentityServer.MongoDB .ToListAsync(GetCancellationToken(cancellationToken)); } - public virtual async Task GetTotalCount() - { - return await GetCountAsync(); - } - public virtual async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().AnyAsync(ar => ar.Id != expectedId && ar.Name == name, GetCancellationToken(cancellationToken)); + return await (await GetMongoQueryableAsync(cancellationToken)) + .AnyAsync(ar => ar.Id != expectedId && ar.Name == name, GetCancellationToken(cancellationToken)); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiScopeRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiScopeRepository.cs index 91a408392f..69faed9dc3 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiScopeRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoApiScopeRepository.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public async Task GetByNameAsync(string scopeName, bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.Name == scopeName) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -31,7 +31,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public async Task> GetListByNameAsync(string[] scopeNames, bool includeDetails = false, CancellationToken cancellationToken = default) { - var query = from scope in GetMongoQueryable() + var query = from scope in (await GetMongoQueryableAsync(cancellationToken)) where scopeNames.Contains(scope.Name) orderby scope.Id select scope; @@ -42,7 +42,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public async Task> GetListAsync(string sorting, int skipCount, int maxResultCount, string filter = null, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.Description.Contains(filter) || @@ -55,7 +55,8 @@ namespace Volo.Abp.IdentityServer.MongoDB public async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().AnyAsync(x => x.Id != expectedId && x.Name == name, GetCancellationToken(cancellationToken)); + return await (await GetMongoQueryableAsync(cancellationToken)) + .AnyAsync(x => x.Id != expectedId && x.Name == name, GetCancellationToken(cancellationToken)); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs index a68f5738d0..bd99461997 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoClientRepository.cs @@ -26,7 +26,7 @@ namespace Volo.Abp.IdentityServer.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.ClientId == clientId) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -40,7 +40,7 @@ namespace Volo.Abp.IdentityServer.MongoDB bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf(!filter.IsNullOrWhiteSpace(), x=>x.ClientId.Contains(filter)) .OrderBy(sorting ?? nameof(Client.ClientName)) .As>() @@ -51,7 +51,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task> GetAllDistinctAllowedCorsOriginsAsync( CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .SelectMany(x => x.AllowedCorsOrigins) .Select(y => y.Origin) .Distinct() @@ -60,12 +60,8 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task CheckClientIdExistAsync(string clientId, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken); - } - - public virtual async Task GetTotalCount() - { - return await GetCountAsync(); + return await (await GetMongoQueryableAsync(cancellationToken)) + .AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs index fc6dc0100a..83e87c0a58 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoDeviceFlowCodesRepository.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.IdentityServer.MongoDB string userCode, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(d => d.UserCode == userCode) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -31,7 +31,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task FindByDeviceCodeAsync(string deviceCode, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(d => d.DeviceCode == deviceCode) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -42,7 +42,7 @@ namespace Volo.Abp.IdentityServer.MongoDB int maxResultCount, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.Expiration != null && x.Expiration < maxExpirationDate) .OrderBy(x => x.ClientId) .Take(maxResultCount) diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs index 15fdf5b00c..84cc5cca0f 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoIdentityResourceRepository.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task> GetListAsync(string sorting, int skipCount, int maxResultCount, string filter, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter) || x.Description.Contains(filter) || x.DisplayName.Contains(filter)) @@ -35,7 +35,7 @@ namespace Volo.Abp.IdentityServer.MongoDB bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.Name == name) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -44,19 +44,15 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task> GetListByScopeNameAsync(string[] scopeNames, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(ar => scopeNames.Contains(ar.Name)) .ToListAsync(GetCancellationToken(cancellationToken)); } - public virtual async Task GetTotalCountAsync() - { - return await GetCountAsync(); - } - public virtual async Task CheckNameExistAsync(string name, Guid? expectedId = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().AnyAsync(ir => ir.Id != expectedId && ir.Name == name, cancellationToken: cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) + .AnyAsync(ir => ir.Id != expectedId && ir.Name == name, cancellationToken: cancellationToken); } } } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs index 6265bcd019..2d4728a7e1 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB/Volo/Abp/IdentityServer/MongoDB/MongoPersistedGrantRepository.cs @@ -21,13 +21,13 @@ namespace Volo.Abp.IdentityServer.MongoDB public async Task> GetListAsync(string subjectId, string sessionId, string clientId, string type, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await Filter(subjectId, sessionId, clientId, type) + return await (await FilterAsync(subjectId, sessionId, clientId, type)) .ToListAsync(GetCancellationToken(cancellationToken)); } public virtual async Task FindByKeyAsync(string key, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.Key == key) .OrderBy(x => x.Id) .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); @@ -35,7 +35,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task> GetListBySubjectIdAsync(string subjectId, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.SubjectId == subjectId) .ToListAsync(GetCancellationToken(cancellationToken)); } @@ -43,7 +43,7 @@ namespace Volo.Abp.IdentityServer.MongoDB public virtual async Task> GetListByExpirationAsync(DateTime maxExpirationDate, int maxResultCount, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.Expiration != null && x.Expiration < maxExpirationDate) .OrderBy(x => x.ClientId) .Take(maxResultCount) @@ -57,7 +57,7 @@ namespace Volo.Abp.IdentityServer.MongoDB string type = null, CancellationToken cancellationToken = default) { - var persistedGrants = await Filter(subjectId, sessionId, clientId, type) + var persistedGrants = await (await FilterAsync(subjectId, sessionId, clientId, type)) .ToListAsync(GetCancellationToken(cancellationToken)); foreach (var persistedGrant in persistedGrants) @@ -82,13 +82,13 @@ namespace Volo.Abp.IdentityServer.MongoDB ); } - private IMongoQueryable Filter( + private async Task> FilterAsync( string subjectId, string sessionId, string clientId, string type) { - return GetMongoQueryable() + return (await GetMongoQueryableAsync()) .WhereIf>(!subjectId.IsNullOrWhiteSpace(), x => x.SubjectId == subjectId) .WhereIf>(!sessionId.IsNullOrWhiteSpace(), x => x.SessionId == sessionId) .WhereIf>(!clientId.IsNullOrWhiteSpace(), x => x.ClientId == clientId) From 4296d82981ef84bcfb20b270c82532403c215400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 21:52:27 +0300 Subject: [PATCH 23/83] implement async in tenant management repo. --- .../EfCoreTenantRepository.cs | 10 +++++++-- .../MongoDb/MongoTenantRepository.cs | 22 +++++++++---------- .../TenantConnectionString_Tests.cs | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs index be11861574..36d28b7659 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); } @@ -50,7 +50,7 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore bool includeDetails = false, CancellationToken cancellationToken = default) { - return await DbSet + return await (await GetDbSetAsync()) .IncludeDetails(includeDetails) .WhereIf( !filter.IsNullOrWhiteSpace(), @@ -72,9 +72,15 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore ).CountAsync(cancellationToken: cancellationToken); } + [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); } + + public override async Task> WithDetailsAsync() + { + return (await GetQueryableAsync()).IncludeDetails(); + } } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs index a074cd973a..abd03ab65d 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs @@ -13,18 +13,18 @@ namespace Volo.Abp.TenantManagement.MongoDB { public class MongoTenantRepository : MongoDbRepository, ITenantRepository { - public MongoTenantRepository(IMongoDbContextProvider dbContextProvider) + public MongoTenantRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) { } public virtual async Task FindByNameAsync( - string name, - bool includeDetails = true, + string name, + bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); } @@ -41,14 +41,14 @@ namespace Volo.Abp.TenantManagement.MongoDB } public virtual async Task> GetListAsync( - string sorting = null, - int maxResultCount = int.MaxValue, - int skipCount = 0, - string filter = null, + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + string filter = null, bool includeDetails = false, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf>( !filter.IsNullOrWhiteSpace(), u => @@ -62,7 +62,7 @@ namespace Volo.Abp.TenantManagement.MongoDB public virtual async Task GetCountAsync(string filter = null, CancellationToken cancellationToken = default) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .WhereIf>( !filter.IsNullOrWhiteSpace(), u => @@ -70,4 +70,4 @@ namespace Volo.Abp.TenantManagement.MongoDB ).CountAsync(cancellationToken: cancellationToken); } } -} \ No newline at end of file +} diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantConnectionString_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantConnectionString_Tests.cs index 24c27db8ae..c6c197ea70 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantConnectionString_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantConnectionString_Tests.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.TenantManagement [Theory] [InlineData("aaa")] [InlineData("bbb")] - public async Task SetValue(string value) + public void SetValue(string value) { var tenantConnectionString = new TenantConnectionString(Guid.NewGuid(), "MyConnString", "MyConnString-Value"); From 3577bdb361f5310ca18b374252b3d615dfaa88b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 23 Dec 2020 22:06:06 +0300 Subject: [PATCH 24/83] Use GetQueryableAsync --- .../AbpPerfTest.WithAbp/Controllers/BookController.cs | 2 +- test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/AbpPerfTest/AbpPerfTest.WithAbp/Controllers/BookController.cs b/test/AbpPerfTest/AbpPerfTest.WithAbp/Controllers/BookController.cs index 7c78937342..ed7f10500b 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithAbp/Controllers/BookController.cs +++ b/test/AbpPerfTest/AbpPerfTest.WithAbp/Controllers/BookController.cs @@ -23,7 +23,7 @@ namespace AbpPerfTest.WithAbp.Controllers [HttpGet] public async Task> GetListAsync() { - var books = await _bookRepository.OrderBy(x => x.Id).Take(10).ToListAsync(); + var books = await (await _bookRepository.GetQueryableAsync()).OrderBy(x => x.Id).Take(10).ToListAsync(); return books .Select(b => new BookDto diff --git a/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx b/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx index 015d6b6767..a21abcac12 100644 --- a/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx +++ b/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx @@ -18,7 +18,7 @@ false 20 - 2000 + 1000 10 false From c7f480d30ed0102f7cb239eeeae833b5216359fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 24 Dec 2020 11:55:46 +0300 Subject: [PATCH 25/83] Add CreateFilteredQueryAsync --- .../Services/AbstractKeyReadOnlyAppService.cs | 26 ++++++++++++++++++- .../Application/Services/CrudAppService.cs | 4 +-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs index b2e11678f8..54123bc843 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AbstractKeyReadOnlyAppService.cs @@ -62,7 +62,7 @@ namespace Volo.Abp.Application.Services { await CheckGetListPolicyAsync(); - var query = CreateFilteredQuery(input); + var query = await CreateFilteredQueryAsync(input); var totalCount = await AsyncExecuter.CountAsync(query); @@ -160,11 +160,35 @@ namespace Volo.Abp.Application.Services /// methods. /// /// The input. + [Obsolete("Override the CreateFilteredQueryAsync method instead.")] protected virtual IQueryable CreateFilteredQuery(TGetListInput input) { return ReadOnlyRepository; } + /// + /// This method should create based on given input. + /// It should filter query if needed, but should not do sorting or paging. + /// Sorting should be done in and paging should be done in + /// methods. + /// + /// The input. + protected virtual async Task> CreateFilteredQueryAsync(TGetListInput input) + { + /* If user has overridden the CreateFilteredQuery method, + * we don't want to make breaking change in this point. + */ +#pragma warning disable 618 + var query = CreateFilteredQuery(input); +#pragma warning restore 618 + if (!ReferenceEquals(query, ReadOnlyRepository)) + { + return query; + } + + return await ReadOnlyRepository.GetQueryableAsync(); + } + /// /// Maps to . /// It internally calls the by default. diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs index 111359d7f3..fffde41ba7 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs @@ -80,12 +80,12 @@ namespace Volo.Abp.Application.Services Repository = repository; } - protected async override Task DeleteByIdAsync(TKey id) + protected override async Task DeleteByIdAsync(TKey id) { await Repository.DeleteAsync(id); } - protected async override Task GetEntityByIdAsync(TKey id) + protected override async Task GetEntityByIdAsync(TKey id) { return await Repository.GetAsync(id); } From 5dad6818f7bea50c15944614d4cf2ef45a8a851e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 24 Dec 2020 12:12:42 +0300 Subject: [PATCH 26/83] Override WithDetailsAsync for EF Core. --- .../EntityFrameworkCore/EfCoreRepository.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index 549318eef8..16c8e6d745 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -312,8 +312,24 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore [Obsolete("Use WithDetailsAsync method.")] public override IQueryable WithDetails(params Expression>[] propertySelectors) { - var query = GetQueryable(); + return IncludeDetails( + GetQueryable(), + propertySelectors + ); + } + public override async Task> WithDetailsAsync(params Expression>[] propertySelectors) + { + return IncludeDetails( + await GetQueryableAsync(), + propertySelectors + ); + } + + private static IQueryable IncludeDetails( + IQueryable query, + Expression>[] propertySelectors) + { if (!propertySelectors.IsNullOrEmpty()) { foreach (var propertySelector in propertySelectors) From d479e70e40401682912a26d9a629122827fdc55a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 24 Dec 2020 15:25:05 +0300 Subject: [PATCH 27/83] Implement async transaction methods. --- .../Repositories/Dapper/DapperRepository.cs | 12 ++++- .../Repositories/Dapper/IDapperRepository.cs | 12 ++++- .../EfCoreRepositoryExtensions.cs | 15 ++++++ .../EntityFrameworkCore/EfCoreRepository.cs | 47 ++++++++++++------- .../EfCoreObjectExtensionManagerExtensions.cs | 2 + .../MemoryDb/MemoryDbRepository.cs | 40 ++++++++-------- .../Volo/Abp/Auditing/Auditing_Tests.cs | 6 +-- .../DbContext_Replace_Tests.cs | 8 ++-- .../Domain/ExtraProperties_Tests.cs | 6 +-- 9 files changed, 96 insertions(+), 52 deletions(-) diff --git a/framework/src/Volo.Abp.Dapper/Volo/Abp/Domain/Repositories/Dapper/DapperRepository.cs b/framework/src/Volo.Abp.Dapper/Volo/Abp/Domain/Repositories/Dapper/DapperRepository.cs index cdb03f8515..39b3eed249 100644 --- a/framework/src/Volo.Abp.Dapper/Volo/Abp/Domain/Repositories/Dapper/DapperRepository.cs +++ b/framework/src/Volo.Abp.Dapper/Volo/Abp/Domain/Repositories/Dapper/DapperRepository.cs @@ -1,4 +1,6 @@ -using System.Data; +using System; +using System.Data; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; using Volo.Abp.EntityFrameworkCore; @@ -16,8 +18,14 @@ namespace Volo.Abp.Domain.Repositories.Dapper _dbContextProvider = dbContextProvider; } + [Obsolete("Use GetDbConnectionAsync method.")] public IDbConnection DbConnection => _dbContextProvider.GetDbContext().Database.GetDbConnection(); + public async Task GetDbConnectionAsync() => (await _dbContextProvider.GetDbContextAsync()).Database.GetDbConnection(); + + [Obsolete("Use GetDbTransactionAsync method.")] public IDbTransaction DbTransaction => _dbContextProvider.GetDbContext().Database.CurrentTransaction?.GetDbTransaction(); + + public async Task GetDbTransactionAsync() => (await _dbContextProvider.GetDbContextAsync()).Database.CurrentTransaction?.GetDbTransaction(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Dapper/Volo/Abp/Domain/Repositories/Dapper/IDapperRepository.cs b/framework/src/Volo.Abp.Dapper/Volo/Abp/Domain/Repositories/Dapper/IDapperRepository.cs index f45be08b54..8145c646a0 100644 --- a/framework/src/Volo.Abp.Dapper/Volo/Abp/Domain/Repositories/Dapper/IDapperRepository.cs +++ b/framework/src/Volo.Abp.Dapper/Volo/Abp/Domain/Repositories/Dapper/IDapperRepository.cs @@ -1,11 +1,19 @@ -using System.Data; +using System; +using System.Data; +using System.Threading.Tasks; namespace Volo.Abp.Domain.Repositories.Dapper { public interface IDapperRepository { + [Obsolete("Use GetDbConnectionAsync method.")] IDbConnection DbConnection { get; } + Task GetDbConnectionAsync(); + + [Obsolete("Use GetDbTransactionAsync method.")] IDbTransaction DbTransaction { get; } + + Task GetDbTransactionAsync(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs index 2463062cde..5049a1b61b 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EfCoreRepositoryExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -7,18 +8,32 @@ namespace Volo.Abp.Domain.Repositories { public static class EfCoreRepositoryExtensions { + [Obsolete("Use GetDbContextAsync method.")] public static DbContext GetDbContext(this IReadOnlyBasicRepository repository) where TEntity : class, IEntity { return repository.ToEfCoreRepository().DbContext; } + public static Task GetDbContextAsync(this IReadOnlyBasicRepository repository) + where TEntity : class, IEntity + { + return repository.ToEfCoreRepository().GetDbContextAsync(); + } + + [Obsolete("Use GetDbSetAsync method.")] public static DbSet GetDbSet(this IReadOnlyBasicRepository repository) where TEntity : class, IEntity { return repository.ToEfCoreRepository().DbSet; } + public static Task> GetDbSetAsync(this IReadOnlyBasicRepository repository) + where TEntity : class, IEntity + { + return repository.ToEfCoreRepository().GetDbSetAsync(); + } + public static IEfCoreRepository ToEfCoreRepository(this IReadOnlyBasicRepository repository) where TEntity : class, IEntity { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index 16c8e6d745..a95ec00e34 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -1,8 +1,6 @@ -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Nito.AsyncEx; using System; using System.Collections.Generic; using System.Linq; @@ -55,7 +53,7 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore private readonly IDbContextProvider _dbContextProvider; private readonly Lazy> _entityOptionsLazy; - public virtual IGuidGenerator GuidGenerator { get; set; } + public IGuidGenerator GuidGenerator { get; set; } public IEfCoreBulkOperationProvider BulkOperationProvider { get; set; } @@ -90,7 +88,11 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore public override async Task InsertManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { - foreach (var entity in entities) + var entityArray = entities.ToArray(); + var dbContext = await GetDbContextAsync(); + cancellationToken = GetCancellationToken(cancellationToken); + + foreach (var entity in entityArray) { CheckAndSetId(entity); } @@ -99,18 +101,18 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore { await BulkOperationProvider.InsertManyAsync( this, - entities, + entityArray, autoSave, cancellationToken ); return; } - await DbSet.AddRangeAsync(entities); + await dbContext.Set().AddRangeAsync(entityArray, cancellationToken); if (autoSave) { - await DbContext.SaveChangesAsync(); + await dbContext.SaveChangesAsync(cancellationToken); } } @@ -132,6 +134,8 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore public override async Task UpdateManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { + cancellationToken = GetCancellationToken(cancellationToken); + if (BulkOperationProvider != null) { await BulkOperationProvider.UpdateManyAsync( @@ -144,11 +148,13 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return; } - DbSet.UpdateRange(entities); + var dbContext = await GetDbContextAsync(); + + dbContext.Set().UpdateRange(entities); if (autoSave) { - await DbContext.SaveChangesAsync(); + await dbContext.SaveChangesAsync(cancellationToken); } } @@ -166,22 +172,27 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore public override async Task DeleteManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { + cancellationToken = GetCancellationToken(cancellationToken); + if (BulkOperationProvider != null) { await BulkOperationProvider.DeleteManyAsync( this, entities, autoSave, - cancellationToken); + cancellationToken + ); return; } - DbSet.RemoveRange(entities); + var dbContext = await GetDbContextAsync(); + + dbContext.RemoveRange(entities); if (autoSave) { - await DbContext.SaveChangesAsync(); + await dbContext.SaveChangesAsync(cancellationToken); } } @@ -225,9 +236,9 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore return (await GetDbSetAsync()).AsQueryable(); } - protected override Task SaveChangesAsync(CancellationToken cancellationToken) + protected override async Task SaveChangesAsync(CancellationToken cancellationToken) { - return DbContext.SaveChangesAsync(cancellationToken); + await (await GetDbContextAsync()).SaveChangesAsync(cancellationToken); } public override async Task FindAsync( @@ -413,9 +424,11 @@ namespace Volo.Abp.Domain.Repositories.EntityFrameworkCore await DeleteAsync(entity, autoSave, cancellationToken); } - public async virtual Task DeleteManyAsync([NotNull] IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) + public virtual async Task DeleteManyAsync(IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) { - var entities = await DbSet.Where(x => ids.Contains(x.Id)).ToListAsync(); + cancellationToken = GetCancellationToken(cancellationToken); + + var entities = await (await GetDbSetAsync()).Where(x => ids.Contains(x.Id)).ToListAsync(cancellationToken); await DeleteManyAsync(entities, autoSave, cancellationToken); } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs index 14fcc93784..54c1909bb3 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs @@ -143,7 +143,9 @@ namespace Volo.Abp.ObjectExtending var propertyBuilder = typeBuilder.Property(property.Type, property.Name); efCoreMapping.EntityTypeAndPropertyBuildAction?.Invoke(typeBuilder, propertyBuilder); +#pragma warning disable 618 efCoreMapping.PropertyBuildAction?.Invoke(propertyBuilder); +#pragma warning restore 618 } } } diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index 0edd7e7604..3318d10d72 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -1,4 +1,3 @@ -using JetBrains.Annotations; using System; using System.Collections.Generic; using System.Linq; @@ -169,27 +168,28 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb await TriggerDomainEventsAsync(entity); } - public override Task FindAsync( + public override async Task FindAsync( Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { - return Task.FromResult(GetQueryable().Where(predicate).SingleOrDefault()); + return (await GetQueryableAsync()).Where(predicate).SingleOrDefault(); } - public async override Task DeleteAsync( + public override async Task DeleteAsync( Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { - var entities = GetQueryable().Where(predicate).ToList(); + var entities = (await GetQueryableAsync()).Where(predicate).ToList(); + foreach (var entity in entities) { await DeleteAsync(entity, autoSave, cancellationToken); } } - public async override Task InsertAsync( + public override async Task InsertAsync( TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) @@ -201,7 +201,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb return entity; } - public async override Task UpdateAsync( + public override async Task UpdateAsync( TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) @@ -225,7 +225,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb return entity; } - public async override Task DeleteAsync( + public override async Task DeleteAsync( TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) @@ -243,27 +243,27 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb } } - public override Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) + public override async Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { - return Task.FromResult(GetQueryable().ToList()); + return (await GetQueryableAsync()).ToList(); } - public override Task GetCountAsync(CancellationToken cancellationToken = default) + public override async Task GetCountAsync(CancellationToken cancellationToken = default) { - return Task.FromResult(GetQueryable().LongCount()); + return (await GetQueryableAsync()).LongCount(); } - public override Task> GetPagedListAsync( + public override async Task> GetPagedListAsync( int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default) { - return Task.FromResult(GetQueryable() + return (await GetQueryableAsync()) .OrderBy(sorting) .PageBy(skipCount, maxResultCount) - .ToList()); + .ToList(); } } @@ -307,9 +307,9 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb return entity; } - public virtual Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) + public virtual async Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { - return Task.FromResult(GetQueryable().FirstOrDefault(e => e.Id.Equals(id))); + return (await GetQueryableAsync()).FirstOrDefault(e => e.Id.Equals(id)); } public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) @@ -317,10 +317,10 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb await DeleteAsync(x => x.Id.Equals(id), autoSave, cancellationToken); } - public virtual async Task DeleteManyAsync([NotNull] IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) + public virtual async Task DeleteManyAsync(IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) { - var entities = await AsyncExecuter.ToListAsync(GetQueryable().Where(x => ids.Contains(x.Id))); - DeleteManyAsync(entities, autoSave, cancellationToken); + var entities = await AsyncExecuter.ToListAsync((await GetQueryableAsync()).Where(x => ids.Contains(x.Id)), cancellationToken); + await DeleteManyAsync(entities, autoSave, cancellationToken); } } } diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs index 8c647c92c4..8ca1228ee6 100644 --- a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/Auditing_Tests.cs @@ -54,13 +54,13 @@ namespace Volo.Abp.Auditing public class MyAuditedObject1 : IMyAuditedObject { - public async virtual Task DoItAsync(InputObject inputObject) + public virtual Task DoItAsync(InputObject inputObject) { - return new ResultObject + return Task.FromResult(new ResultObject { Value1 = inputObject.Value1 + "-result", Value2 = inputObject.Value2 + 1 - }; + }); } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs index 7bc4af2e31..977cb8522a 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs @@ -26,12 +26,12 @@ namespace Volo.Abp.EntityFrameworkCore { (ServiceProvider.GetRequiredService() is TestAppDbContext).ShouldBeTrue(); - using (_unitOfWorkManager.Begin()) + using (var uow = _unitOfWorkManager.Begin()) { - (_dummyRepository.GetDbContext() is IThirdDbContext).ShouldBeTrue(); - (_dummyRepository.GetDbContext() is TestAppDbContext).ShouldBeTrue(); + ((await _dummyRepository.GetDbContextAsync()) is IThirdDbContext).ShouldBeTrue(); + ((await _dummyRepository.GetDbContextAsync()) is TestAppDbContext).ShouldBeTrue(); - await _unitOfWorkManager.Current.CompleteAsync(); + await uow.CompleteAsync(); } } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/ExtraProperties_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/ExtraProperties_Tests.cs index f94f16c390..aa1e0080b5 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/ExtraProperties_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/ExtraProperties_Tests.cs @@ -44,15 +44,13 @@ namespace Volo.Abp.EntityFrameworkCore.Domain [Fact] public async Task An_Extra_Property_Configured_As_Extension2() { - await WithUnitOfWorkAsync(() => + await WithUnitOfWorkAsync(async () => { - var entityEntry = CityRepository.GetDbContext().Attach(new City(Guid.NewGuid(), "NewYork")); + var entityEntry = (await CityRepository.GetDbContextAsync()).Attach(new City(Guid.NewGuid(), "NewYork")); var indexes = entityEntry.Metadata.GetIndexes().ToList(); indexes.ShouldNotBeEmpty(); indexes.ShouldContain(x => x.IsUnique); - return Task.CompletedTask; }); - } } } From 3094f577a6b55716aa7876eb595673eb813cbc8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 24 Dec 2020 15:27:03 +0300 Subject: [PATCH 28/83] Update PersonDapperRepository.cs --- .../Dapper/Repositories/PersonDapperRepository.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository.cs b/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository.cs index b5127e3d7e..e4510a366a 100644 --- a/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository.cs +++ b/framework/test/Volo.Abp.Dapper.Tests/Volo/Abp/Dapper/Repositories/PersonDapperRepository.cs @@ -17,14 +17,19 @@ namespace Volo.Abp.Dapper.Repositories public virtual async Task> GetAllPersonNames() { - return (await DbConnection.QueryAsync("select Name from People", transaction: DbTransaction)) - .ToList(); + return (await (await GetDbConnectionAsync()) + .QueryAsync( + "select Name from People", + transaction: await GetDbTransactionAsync() + ) + ).ToList(); } public virtual async Task UpdatePersonNames(string name) { - return await DbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name }, - DbTransaction); + return await (await GetDbConnectionAsync()) + .ExecuteAsync("update People set Name = @NewName", new {NewName = name}, + await GetDbTransactionAsync()); } } -} \ No newline at end of file +} From b318ee8799ce823814b5bb23a642226784550ab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 24 Dec 2020 15:35:09 +0300 Subject: [PATCH 29/83] Use ICancellationTokenProvider --- .../UnitOfWorkDbContextProvider.cs | 20 ++++++++++++++----- .../UnitOfWorkMongoDbContextProvider.cs | 13 ++++++++++-- .../Volo/Abp/Uow/UnitOfWorkInterceptor.cs | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs index 22df5fddf5..3539830beb 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; @@ -8,6 +9,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.Uow.EntityFrameworkCore { @@ -20,13 +22,16 @@ namespace Volo.Abp.Uow.EntityFrameworkCore private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IConnectionStringResolver _connectionStringResolver; + private readonly ICancellationTokenProvider _cancellationTokenProvider; public UnitOfWorkDbContextProvider( IUnitOfWorkManager unitOfWorkManager, - IConnectionStringResolver connectionStringResolver) + IConnectionStringResolver connectionStringResolver, + ICancellationTokenProvider cancellationTokenProvider) { _unitOfWorkManager = unitOfWorkManager; _connectionStringResolver = connectionStringResolver; + _cancellationTokenProvider = cancellationTokenProvider; Logger = NullLogger>.Instance; } @@ -194,8 +199,8 @@ namespace Volo.Abp.Uow.EntityFrameworkCore var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); var dbTransaction = unitOfWork.Options.IsolationLevel.HasValue - ? await dbContext.Database.BeginTransactionAsync(unitOfWork.Options.IsolationLevel.Value) - : await dbContext.Database.BeginTransactionAsync(); + ? await dbContext.Database.BeginTransactionAsync(unitOfWork.Options.IsolationLevel.Value, GetCancellationToken()) + : await dbContext.Database.BeginTransactionAsync(GetCancellationToken()); unitOfWork.AddTransactionApi( transactionApiKey, @@ -215,11 +220,11 @@ namespace Volo.Abp.Uow.EntityFrameworkCore if (dbContext.As().HasRelationalTransactionManager()) { - await dbContext.Database.UseTransactionAsync(activeTransaction.DbContextTransaction.GetDbTransaction()); + await dbContext.Database.UseTransactionAsync(activeTransaction.DbContextTransaction.GetDbTransaction(), GetCancellationToken()); } else { - await dbContext.Database.BeginTransactionAsync(); //TODO: Why not using the new created transaction? + await dbContext.Database.BeginTransactionAsync(GetCancellationToken()); //TODO: Why not using the new created transaction? } activeTransaction.AttendedDbContexts.Add(dbContext); @@ -227,5 +232,10 @@ namespace Volo.Abp.Uow.EntityFrameworkCore return dbContext; } } + + protected virtual CancellationToken GetCancellationToken(CancellationToken preferredValue = default) + { + return _cancellationTokenProvider.FallbackToProvider(preferredValue); + } } } diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs index 8a9ecd5de6..1ce1dc4649 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs @@ -6,6 +6,7 @@ using MongoDB.Bson; using MongoDB.Driver; using Volo.Abp.Data; using Volo.Abp.MongoDB; +using Volo.Abp.Threading; namespace Volo.Abp.Uow.MongoDB { @@ -14,13 +15,16 @@ namespace Volo.Abp.Uow.MongoDB { private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IConnectionStringResolver _connectionStringResolver; + private readonly ICancellationTokenProvider _cancellationTokenProvider; public UnitOfWorkMongoDbContextProvider( IUnitOfWorkManager unitOfWorkManager, - IConnectionStringResolver connectionStringResolver) + IConnectionStringResolver connectionStringResolver, + ICancellationTokenProvider cancellationTokenProvider) { _unitOfWorkManager = unitOfWorkManager; _connectionStringResolver = connectionStringResolver; + _cancellationTokenProvider = cancellationTokenProvider; } [Obsolete("Use CreateDbContextAsync")] @@ -183,7 +187,7 @@ namespace Volo.Abp.Uow.MongoDB if (activeTransaction?.SessionHandle == null) { - var session = await client.StartSessionAsync(cancellationToken: cancellationToken); + var session = await client.StartSessionAsync(cancellationToken: GetCancellationToken(cancellationToken)); if (unitOfWork.Options.Timeout.HasValue) { @@ -206,5 +210,10 @@ namespace Volo.Abp.Uow.MongoDB return dbContext; } + + protected virtual CancellationToken GetCancellationToken(CancellationToken preferredValue = default) + { + return _cancellationTokenProvider.FallbackToProvider(preferredValue); + } } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs index f2ed948eb1..464b6bb871 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkInterceptor.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.Uow _defaultOptions = options.Value; } - public async override Task InterceptAsync(IAbpMethodInvocation invocation) + public override async Task InterceptAsync(IAbpMethodInvocation invocation) { if (!UnitOfWorkHelper.IsUnitOfWorkMethod(invocation.Method, out var unitOfWorkAttribute)) { From d8723d2fce25ef7022a97ed78f02e756460a3901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 24 Dec 2020 16:03:31 +0300 Subject: [PATCH 30/83] Update BookController.cs --- .../AbpPerfTest.WithAbp/Controllers/BookController.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/AbpPerfTest/AbpPerfTest.WithAbp/Controllers/BookController.cs b/test/AbpPerfTest/AbpPerfTest.WithAbp/Controllers/BookController.cs index ed7f10500b..1533e95f71 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithAbp/Controllers/BookController.cs +++ b/test/AbpPerfTest/AbpPerfTest.WithAbp/Controllers/BookController.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using AbpPerfTest.WithAbp.Dtos; using AbpPerfTest.WithAbp.Entities; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Repositories; namespace AbpPerfTest.WithAbp.Controllers @@ -23,7 +22,7 @@ namespace AbpPerfTest.WithAbp.Controllers [HttpGet] public async Task> GetListAsync() { - var books = await (await _bookRepository.GetQueryableAsync()).OrderBy(x => x.Id).Take(10).ToListAsync(); + var books = await _bookRepository.GetPagedListAsync(0, 10, "Id"); return books .Select(b => new BookDto From 497aec6c975317a162cd742387854ddde0fcd7b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 24 Dec 2020 16:14:35 +0300 Subject: [PATCH 31/83] Enable transactions --- test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs | 2 +- test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json | 4 ++-- test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx | 6 +++--- test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs b/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs index 1cd88989e6..3846cdd3de 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs +++ b/test/AbpPerfTest/AbpPerfTest.WithAbp/AppModule.cs @@ -33,7 +33,7 @@ namespace AbpPerfTest.WithAbp Configure(options => { - options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; + options.TransactionBehavior = UnitOfWorkTransactionBehavior.Auto; }); } diff --git a/test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json b/test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json index 9cd22c72c3..729af8691d 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json +++ b/test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json @@ -1,8 +1,8 @@ { "Logging": { "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", + "Default": "Error", + "Microsoft": "Error", "Microsoft.Hosting.Lifetime": "Information" } }, diff --git a/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx b/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx index a21abcac12..0c08c60f20 100644 --- a/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx +++ b/test/AbpPerfTest/_jmeter/SimpleTestPlan.jmx @@ -18,7 +18,7 @@ false 20 - 1000 + 2000 10 false @@ -84,7 +84,7 @@ - + true @@ -115,7 +115,7 @@ - + diff --git a/test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx b/test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx index eee33504c1..c7d6b3292c 100644 --- a/test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx +++ b/test/AbpPerfTest/_jmeter/SimpleTestPlanWithoutAbp.jmx @@ -18,7 +18,7 @@ false 20 - 1000 + 500 10 false @@ -84,7 +84,7 @@ - + true @@ -115,7 +115,7 @@ - + From db6d5b50aa874489b1c6d42c445a3fa33eb1727b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 24 Dec 2020 18:16:49 +0300 Subject: [PATCH 32/83] Make multi-tenancy connection string resolving async. --- .../Data/DefaultConnectionStringResolver.cs | 16 +++++- .../Abp/Data/IConnectionStringResolver.cs | 8 ++- .../IConnectionStringResolverExtensions.cs | 14 ++++- .../DbContextOptionsFactory.cs | 4 ++ .../UnitOfWorkDbContextProvider.cs | 2 +- .../MemoryDb/IMemoryDbRepository.cs | 9 +++- .../MemoryDb/MemoryDbRepository.cs | 35 ++++++++---- .../MemoryDbCoreRepositoryExtensions.cs | 17 +++++- .../Abp/MemoryDb/IMemoryDatabaseProvider.cs | 12 ++++- .../UnitOfWorkMemoryDatabaseProvider.cs | 36 +++++++++++-- .../UnitOfWorkMongoDbContextProvider.cs | 2 +- .../Volo/Abp/MultiTenancy/ITenantStore.cs | 4 +- .../MultiTenantConnectionStringResolver.cs | 53 +++++++++++++++++++ .../Data/ConnectionStringResolver_Tests.cs | 15 +++--- .../Abp/TestApp/MemoryDb/CityRepository.cs | 8 +-- ...ltiTenantConnectionStringResolver_Tests.cs | 21 ++++---- .../Abp/TenantManagement/ITenantRepository.cs | 18 ++++--- .../Volo/Abp/TenantManagement/TenantStore.cs | 4 +- .../EfCoreTenantRepository.cs | 2 + .../MongoDb/MongoTenantRepository.cs | 2 + 20 files changed, 226 insertions(+), 56 deletions(-) diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DefaultConnectionStringResolver.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DefaultConnectionStringResolver.cs index 84221fb271..4d5ce2fb27 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DefaultConnectionStringResolver.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DefaultConnectionStringResolver.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -14,7 +15,18 @@ namespace Volo.Abp.Data Options = options.Value; } + [Obsolete("Use ResolveAsync method.")] public virtual string Resolve(string connectionStringName = null) + { + return ResolveInternal(connectionStringName); + } + + public virtual Task ResolveAsync(string connectionStringName = null) + { + return Task.FromResult(ResolveInternal(connectionStringName)); + } + + private string ResolveInternal(string connectionStringName) { //Get module specific value if provided if (!connectionStringName.IsNullOrEmpty()) @@ -25,9 +37,9 @@ namespace Volo.Abp.Data return moduleConnString; } } - + //Get default value return Options.ConnectionStrings.Default; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolver.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolver.cs index e9344ef66a..3bc8e22d78 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolver.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolver.cs @@ -1,10 +1,16 @@ -using JetBrains.Annotations; +using System; +using System.Threading.Tasks; +using JetBrains.Annotations; namespace Volo.Abp.Data { public interface IConnectionStringResolver { [NotNull] + [Obsolete("Use ResolveAsync method.")] string Resolve(string connectionStringName = null); + + [NotNull] + Task ResolveAsync(string connectionStringName = null); } } diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolverExtensions.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolverExtensions.cs index e3a89e24e8..1fa097964c 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolverExtensions.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolverExtensions.cs @@ -1,10 +1,22 @@ -namespace Volo.Abp.Data +using System; +using System.Threading.Tasks; +using JetBrains.Annotations; + +namespace Volo.Abp.Data { public static class ConnectionStringResolverExtensions { + [NotNull] + [Obsolete("Use ResolveAsync method")] public static string Resolve(this IConnectionStringResolver resolver) { return resolver.Resolve(ConnectionStringNameAttribute.GetConnStringName()); } + + [NotNull] + public static Task ResolveAsync(this IConnectionStringResolver resolver) + { + return resolver.ResolveAsync(ConnectionStringNameAttribute.GetConnStringName()); + } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs index a2d52eac48..0147de12fb 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/DependencyInjection/DbContextOptionsFactory.cs @@ -86,7 +86,11 @@ namespace Volo.Abp.EntityFrameworkCore.DependencyInjection } var connectionStringName = ConnectionStringNameAttribute.GetConnStringName(); + + //Use DefaultConnectionStringResolver.Resolve when we remove IConnectionStringResolver.Resolve +#pragma warning disable 618 var connectionString = serviceProvider.GetRequiredService().Resolve(connectionStringName); +#pragma warning restore 618 return new DbContextCreationContext( connectionStringName, diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs index 3539830beb..7490862b95 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs @@ -71,7 +71,7 @@ namespace Volo.Abp.Uow.EntityFrameworkCore } var connectionStringName = ConnectionStringNameAttribute.GetConnStringName(); - var connectionString = _connectionStringResolver.Resolve(connectionStringName); + var connectionString = await _connectionStringResolver.ResolveAsync(connectionStringName); var dbContextKey = $"{typeof(TDbContext).FullName}_{connectionString}"; diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/IMemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/IMemoryDbRepository.cs index c179b68931..6d4fb7d896 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/IMemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/IMemoryDbRepository.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Threading.Tasks; using Volo.Abp.Domain.Entities; namespace Volo.Abp.Domain.Repositories.MemoryDb @@ -6,9 +7,15 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb public interface IMemoryDbRepository : IRepository where TEntity : class, IEntity { + [Obsolete("Use GetDatabaseAsync() method.")] IMemoryDatabase Database { get; } + [Obsolete("Use GetCollectionAsync() method.")] IMemoryDatabaseCollection Collection { get; } + + Task GetDatabaseAsync(); + + Task> GetCollectionAsync(); } public interface IMemoryDbRepository : IMemoryDbRepository, IRepository diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index 3318d10d72..811c51ed5f 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -21,10 +21,22 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { //TODO: Add dbcontext just like mongodb implementation! + [Obsolete("Use GetCollectionAsync method.")] public virtual IMemoryDatabaseCollection Collection => Database.Collection(); + public async Task> GetCollectionAsync() + { + return (await GetDatabaseAsync()).Collection(); + } + + [Obsolete("Use GetDatabaseAsync method.")] public virtual IMemoryDatabase Database => DatabaseProvider.GetDatabase(); + public Task GetDatabaseAsync() + { + return DatabaseProvider.GetDatabaseAsync(); + } + protected IMemoryDatabaseProvider DatabaseProvider { get; } public ILocalEventBus LocalEventBus { get; set; } @@ -52,9 +64,9 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb return ApplyDataFilters(Collection.AsQueryable()); } - public override Task> GetQueryableAsync() + public override async Task> GetQueryableAsync() { - return Task.FromResult(ApplyDataFilters(Collection.AsQueryable())); + return ApplyDataFilters((await GetCollectionAsync()).AsQueryable()); } protected virtual async Task TriggerDomainEventsAsync(object entity) @@ -196,7 +208,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { await ApplyAbpConceptsForAddedEntityAsync(entity); - Collection.Add(entity); + (await GetCollectionAsync()).Add(entity); return entity; } @@ -220,7 +232,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb await TriggerDomainEventsAsync(entity); - Collection.Update(entity); + (await GetCollectionAsync()).Update(entity); return entity; } @@ -235,11 +247,11 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb if (entity is ISoftDelete softDeleteEntity && !IsHardDeleted(entity)) { softDeleteEntity.IsDeleted = true; - Collection.Update(entity); + (await GetCollectionAsync()).Update(entity); } else { - Collection.Remove(entity); + (await GetCollectionAsync()).Remove(entity); } } @@ -276,13 +288,13 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { } - public override Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + public override async Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { - SetIdIfNeeded(entity); - return base.InsertAsync(entity, autoSave, cancellationToken); + await SetIdIfNeededAsync(entity); + return await base.InsertAsync(entity, autoSave, cancellationToken); } - protected virtual void SetIdIfNeeded(TEntity entity) + protected virtual async Task SetIdIfNeededAsync(TEntity entity) { if (typeof(TKey) == typeof(int) || typeof(TKey) == typeof(long) || @@ -290,7 +302,8 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { if (EntityHelper.HasDefaultId(entity)) { - EntityHelper.TrySetId(entity, () => Database.GenerateNextId()); + var nextId = (await GetDatabaseAsync()).GenerateNextId(); + EntityHelper.TrySetId(entity, () => nextId); } } } diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDbCoreRepositoryExtensions.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDbCoreRepositoryExtensions.cs index 1547a581e5..003bf8b034 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDbCoreRepositoryExtensions.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDbCoreRepositoryExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.MemoryDb; @@ -7,18 +8,32 @@ namespace Volo.Abp.Domain.Repositories { public static class MemoryDbCoreRepositoryExtensions { + [Obsolete("Use GetDatabaseAsync method.")] public static IMemoryDatabase GetDatabase(this IBasicRepository repository) where TEntity : class, IEntity { return repository.ToMemoryDbRepository().Database; } + public static Task GetDatabaseAsync(this IBasicRepository repository) + where TEntity : class, IEntity + { + return repository.ToMemoryDbRepository().GetDatabaseAsync(); + } + + [Obsolete("Use GetCollectionAsync method.")] public static IMemoryDatabaseCollection GetCollection(this IBasicRepository repository) where TEntity : class, IEntity { return repository.ToMemoryDbRepository().Collection; } + public static Task> GetCollectionAsync(this IBasicRepository repository) + where TEntity : class, IEntity + { + return repository.ToMemoryDbRepository().GetCollectionAsync(); + } + public static IMemoryDbRepository ToMemoryDbRepository(this IBasicRepository repository) where TEntity : class, IEntity { @@ -31,4 +46,4 @@ namespace Volo.Abp.Domain.Repositories return memoryDbRepository; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/IMemoryDatabaseProvider.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/IMemoryDatabaseProvider.cs index ad4456c793..514b079e69 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/IMemoryDatabaseProvider.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/MemoryDb/IMemoryDatabaseProvider.cs @@ -1,12 +1,20 @@ -using Volo.Abp.Domain.Repositories.MemoryDb; +using System; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories.MemoryDb; namespace Volo.Abp.MemoryDb { public interface IMemoryDatabaseProvider where TMemoryDbContext : MemoryDbContext { + [Obsolete("Use GetDbContextAsync method.")] TMemoryDbContext DbContext { get; } + Task GetDbContextAsync(); + + [Obsolete("Use GetDatabaseAsync method.")] IMemoryDatabase GetDatabase(); + + Task GetDatabaseAsync(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Uow/MemoryDb/UnitOfWorkMemoryDatabaseProvider.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Uow/MemoryDb/UnitOfWorkMemoryDatabaseProvider.cs index 24c1cdaeb9..c2c5a1df71 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Uow/MemoryDb/UnitOfWorkMemoryDatabaseProvider.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Uow/MemoryDb/UnitOfWorkMemoryDatabaseProvider.cs @@ -1,4 +1,6 @@ -using Volo.Abp.Data; +using System; +using System.Threading.Tasks; +using Volo.Abp.Data; using Volo.Abp.Domain.Repositories.MemoryDb; using Volo.Abp.MemoryDb; @@ -8,7 +10,7 @@ namespace Volo.Abp.Uow.MemoryDb where TMemoryDbContext : MemoryDbContext { public TMemoryDbContext DbContext { get; } - + private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IConnectionStringResolver _connectionStringResolver; private readonly MemoryDatabaseManager _memoryDatabaseManager; @@ -16,7 +18,7 @@ namespace Volo.Abp.Uow.MemoryDb public UnitOfWorkMemoryDatabaseProvider( IUnitOfWorkManager unitOfWorkManager, IConnectionStringResolver connectionStringResolver, - TMemoryDbContext dbContext, + TMemoryDbContext dbContext, MemoryDatabaseManager memoryDatabaseManager) { _unitOfWorkManager = unitOfWorkManager; @@ -25,6 +27,12 @@ namespace Volo.Abp.Uow.MemoryDb _memoryDatabaseManager = memoryDatabaseManager; } + public Task GetDbContextAsync() + { + return Task.FromResult(DbContext); + } + + [Obsolete("Use GetDatabaseAsync method.")] public IMemoryDatabase GetDatabase() { var unitOfWork = _unitOfWorkManager.Current; @@ -44,5 +52,25 @@ namespace Volo.Abp.Uow.MemoryDb return ((MemoryDbDatabaseApi)databaseApi).Database; } + + public async Task GetDatabaseAsync() + { + var unitOfWork = _unitOfWorkManager.Current; + if (unitOfWork == null) + { + throw new AbpException($"A {nameof(IMemoryDatabase)} instance can only be created inside a unit of work!"); + } + + var connectionString = await _connectionStringResolver.ResolveAsync(); + var dbContextKey = $"{typeof(TMemoryDbContext).FullName}_{connectionString}"; + + var databaseApi = unitOfWork.GetOrAddDatabaseApi( + dbContextKey, + () => new MemoryDbDatabaseApi( + _memoryDatabaseManager.Get(connectionString) + )); + + return ((MemoryDbDatabaseApi)databaseApi).Database; + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs index 1ce1dc4649..a3d6fe7cf4 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs @@ -64,7 +64,7 @@ namespace Volo.Abp.Uow.MongoDB $"A {nameof(IMongoDatabase)} instance can only be created inside a unit of work!"); } - var connectionString = _connectionStringResolver.Resolve(); + var connectionString = await _connectionStringResolver.ResolveAsync(); var dbContextKey = $"{typeof(TMongoDbContext).FullName}_{connectionString}"; var mongoUrl = new MongoUrl(connectionString); diff --git a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantStore.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantStore.cs index 7125a97405..6c66044e37 100644 --- a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantStore.cs +++ b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/ITenantStore.cs @@ -9,8 +9,10 @@ namespace Volo.Abp.MultiTenancy Task FindAsync(Guid id); + [Obsolete("Use FindAsync method.")] TenantConfiguration Find(string name); + [Obsolete("Use FindAsync method.")] TenantConfiguration Find(Guid id); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantConnectionStringResolver.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantConnectionStringResolver.cs index d92409fe0d..0d82419013 100644 --- a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantConnectionStringResolver.cs +++ b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenantConnectionStringResolver.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.Data; @@ -23,6 +24,58 @@ namespace Volo.Abp.MultiTenancy _serviceProvider = serviceProvider; } + public override async Task ResolveAsync(string connectionStringName = null) + { + //No current tenant, fallback to default logic + if (_currentTenant.Id == null) + { + return await base.ResolveAsync(connectionStringName); + } + + using (var serviceScope = _serviceProvider.CreateScope()) + { + var tenantStore = serviceScope + .ServiceProvider + .GetRequiredService(); + + var tenant = await tenantStore.FindAsync(_currentTenant.Id.Value); + + if (tenant?.ConnectionStrings == null) + { + return await base.ResolveAsync(connectionStringName); + } + + //Requesting default connection string + if (connectionStringName == null) + { + return tenant.ConnectionStrings.Default ?? + Options.ConnectionStrings.Default; + } + + //Requesting specific connection string + var connString = tenant.ConnectionStrings.GetOrDefault(connectionStringName); + if (connString != null) + { + return connString; + } + + /* Requested a specific connection string, but it's not specified for the tenant. + * - If it's specified in options, use it. + * - If not, use tenant's default conn string. + */ + + var connStringInOptions = Options.ConnectionStrings.GetOrDefault(connectionStringName); + if (connStringInOptions != null) + { + return connStringInOptions; + } + + return tenant.ConnectionStrings.Default ?? + Options.ConnectionStrings.Default; + } + } + + [Obsolete("Use ResolveAsync method.")] public override string Resolve(string connectionStringName = null) { //No current tenant, fallback to default logic diff --git a/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs b/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs index d13c89671e..3971c29ff0 100644 --- a/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs +++ b/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Modularity; using Volo.Abp.Testing; @@ -21,21 +22,21 @@ namespace Volo.Abp.Data } [Fact] - public void Should_Get_Default_ConnString_By_Default() + public async Task Should_Get_Default_ConnString_By_Default() { - _connectionStringResolver.Resolve().ShouldBe(DefaultConnString); + (await _connectionStringResolver.ResolveAsync()).ShouldBe(DefaultConnString); } [Fact] - public void Should_Get_Specific_ConnString_IfDefined() + public async Task Should_Get_Specific_ConnString_IfDefined() { - _connectionStringResolver.Resolve(Database1Name).ShouldBe(Database1ConnString); + (await _connectionStringResolver.ResolveAsync(Database1Name)).ShouldBe(Database1ConnString); } [Fact] - public void Should_Get_Default_ConnString_If_Not_Specified() + public async Task Should_Get_Default_ConnString_If_Not_Specified() { - _connectionStringResolver.Resolve(Database2Name).ShouldBe(DefaultConnString); + (await _connectionStringResolver.ResolveAsync(Database2Name)).ShouldBe(DefaultConnString); } [DependsOn(typeof(AbpDataModule))] diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/CityRepository.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/CityRepository.cs index b6d43dc875..309339e09d 100644 --- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/CityRepository.cs +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/TestApp/MemoryDb/CityRepository.cs @@ -10,21 +10,21 @@ namespace Volo.Abp.TestApp.MemoryDb { public class CityRepository : MemoryDbRepository, ICityRepository { - public CityRepository(IMemoryDatabaseProvider databaseProvider) + public CityRepository(IMemoryDatabaseProvider databaseProvider) : base(databaseProvider) { } - public Task FindByNameAsync(string name) + public async Task FindByNameAsync(string name) { - return Task.FromResult(Collection.FirstOrDefault(c => c.Name == name)); + return (await GetCollectionAsync()).FirstOrDefault(c => c.Name == name); } public async Task> GetPeopleInTheCityAsync(string cityName) { var city = await FindByNameAsync(cityName); - return Database.Collection().Where(p => p.CityId == city.Id).ToList(); + return (await GetDatabaseAsync()).Collection().Where(p => p.CityId == city.Id).ToList(); } } } diff --git a/framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/Data/MultiTenancy/MultiTenantConnectionStringResolver_Tests.cs b/framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/Data/MultiTenancy/MultiTenantConnectionStringResolver_Tests.cs index a6e5fab1c8..f6af2bde72 100644 --- a/framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/Data/MultiTenancy/MultiTenantConnectionStringResolver_Tests.cs +++ b/framework/test/Volo.Abp.MultiTenancy.Tests/Volo/Abp/Data/MultiTenancy/MultiTenantConnectionStringResolver_Tests.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.MultiTenancy; @@ -49,28 +50,28 @@ namespace Volo.Abp.Data.MultiTenancy } [Fact] - public void All_Tests() + public async Task All_Tests() { //No tenant in current context - _connectionResolver.Resolve().ShouldBe("default-value"); - _connectionResolver.Resolve("db1").ShouldBe("db1-default-value"); + (await _connectionResolver.ResolveAsync()).ShouldBe("default-value"); + (await _connectionResolver.ResolveAsync("db1")).ShouldBe("db1-default-value"); - //Overrided connection strings for tenant1 + //Overriden connection strings for tenant1 using (_currentTenant.Change(_tenant1Id)) { - _connectionResolver.Resolve().ShouldBe("tenant1-default-value"); - _connectionResolver.Resolve("db1").ShouldBe("tenant1-db1-value"); + (await _connectionResolver.ResolveAsync()).ShouldBe("tenant1-default-value"); + (await _connectionResolver.ResolveAsync("db1")).ShouldBe("tenant1-db1-value"); } //No tenant in current context - _connectionResolver.Resolve().ShouldBe("default-value"); - _connectionResolver.Resolve("db1").ShouldBe("db1-default-value"); + (await _connectionResolver.ResolveAsync()).ShouldBe("default-value"); + (await _connectionResolver.ResolveAsync("db1")).ShouldBe("db1-default-value"); //Undefined connection strings for tenant2 using (_currentTenant.Change(_tenant2Id)) { - _connectionResolver.Resolve().ShouldBe("default-value"); - _connectionResolver.Resolve("db1").ShouldBe("db1-default-value"); + (await _connectionResolver.ResolveAsync()).ShouldBe("default-value"); + (await _connectionResolver.ResolveAsync("db1")).ShouldBe("db1-default-value"); } } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs index 1feca866a2..8a3fc0b19a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/ITenantRepository.cs @@ -9,30 +9,32 @@ namespace Volo.Abp.TenantManagement public interface ITenantRepository : IBasicRepository { Task FindByNameAsync( - string name, - bool includeDetails = true, + string name, + bool includeDetails = true, CancellationToken cancellationToken = default); + [Obsolete("Use FindByNameAsync method.")] Tenant FindByName( string name, bool includeDetails = true ); + [Obsolete("Use FindAsync method.")] Tenant FindById( Guid id, bool includeDetails = true ); Task> GetListAsync( - string sorting = null, - int maxResultCount = int.MaxValue, - int skipCount = 0, - string filter = null, + string sorting = null, + int maxResultCount = int.MaxValue, + int skipCount = 0, + string filter = null, bool includeDetails = false, CancellationToken cancellationToken = default); Task GetCountAsync( - string filter = null, + string filter = null, CancellationToken cancellationToken = default); } -} \ No newline at end of file +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs index 5847ed7d89..00b9ef0963 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantStore.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.TenantManagement protected ICurrentTenant CurrentTenant { get; } public TenantStore( - ITenantRepository tenantRepository, + ITenantRepository tenantRepository, IObjectMapper objectMapper, ICurrentTenant currentTenant) { @@ -52,6 +52,7 @@ namespace Volo.Abp.TenantManagement } } + [Obsolete("Use FindAsync method.")] public virtual TenantConfiguration Find(string name) { using (CurrentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! @@ -66,6 +67,7 @@ namespace Volo.Abp.TenantManagement } } + [Obsolete("Use FindAsync method.")] public virtual TenantConfiguration Find(Guid id) { using (CurrentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities! diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs index 36d28b7659..4b6208e232 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore/Volo/Abp/TenantManagement/EntityFrameworkCore/EfCoreTenantRepository.cs @@ -28,6 +28,7 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); } + [Obsolete("Use FindByNameAsync method.")] public virtual Tenant FindByName(string name, bool includeDetails = true) { return DbSet @@ -35,6 +36,7 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore .FirstOrDefault(t => t.Name == name); } + [Obsolete("Use FindAsync method.")] public virtual Tenant FindById(Guid id, bool includeDetails = true) { return DbSet diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs index abd03ab65d..a2805f7333 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB/Volo/Abp/TenantManagement/MongoDb/MongoTenantRepository.cs @@ -28,12 +28,14 @@ namespace Volo.Abp.TenantManagement.MongoDB .FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken)); } + [Obsolete("Use FindByNameAsync method.")] public virtual Tenant FindByName(string name, bool includeDetails = true) { return GetMongoQueryable() .FirstOrDefault(t => t.Name == name); } + [Obsolete("Use FindAsync method.")] public virtual Tenant FindById(Guid id, bool includeDetails = true) { return GetMongoQueryable() From 2c6ae3a13e07c06b55d560aee428b100b745a1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 25 Dec 2020 11:56:08 +0300 Subject: [PATCH 33/83] Update MongoDbRepository.cs --- .../Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index ab0c063191..53c291a178 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -460,7 +460,11 @@ namespace Volo.Abp.Domain.Repositories.MongoDB [Obsolete("Use GetMongoQueryableAsync method.")] public virtual IMongoQueryable GetMongoQueryable() { - return ApplyDataFilters(SessionHandle != null ? Collection.AsQueryable(SessionHandle) : Collection.AsQueryable()); + return ApplyDataFilters( + SessionHandle != null + ? Collection.AsQueryable(SessionHandle) + : Collection.AsQueryable() + ); } public async Task> GetMongoQueryableAsync(CancellationToken cancellationToken = default) From ad49f51c351ba9963d434c4d9ac15791636f4714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 25 Dec 2020 20:53:22 +0300 Subject: [PATCH 34/83] Better warning message --- .../UnitOfWorkDbContextProvider.cs | 8 ++++++-- .../Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs | 13 +++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs index 7490862b95..143a5659cc 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs @@ -39,8 +39,12 @@ namespace Volo.Abp.Uow.EntityFrameworkCore [Obsolete("Use GetDbContextAsync method.")] public TDbContext GetDbContext() { - Logger.LogWarning("UnitOfWorkDbContextProvider.GetDbContext is deprecated. Use GetDbContextAsync instead!"); - Logger.LogWarning(Environment.StackTrace); + Logger.LogWarning( + "UnitOfWorkDbContextProvider.GetDbContext is deprecated. Use GetDbContextAsync instead! " + + "You are probably using LINQ (LINQ extensions) directly on a repository. In this case, use repository.GetQueryableAsync() method " + + "to obtain an IQueryable instance and use LINQ (LINQ extensions) on this object. " + ); + Logger.LogWarning(Environment.StackTrace.Truncate(2048)); var unitOfWork = _unitOfWorkManager.Current; if (unitOfWork == null) diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs index a3d6fe7cf4..724e7673fc 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Uow/MongoDB/UnitOfWorkMongoDbContextProvider.cs @@ -2,6 +2,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using MongoDB.Bson; using MongoDB.Driver; using Volo.Abp.Data; @@ -13,6 +15,8 @@ namespace Volo.Abp.Uow.MongoDB public class UnitOfWorkMongoDbContextProvider : IMongoDbContextProvider where TMongoDbContext : IAbpMongoDbContext { + public ILogger> Logger { get; set; } + private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IConnectionStringResolver _connectionStringResolver; private readonly ICancellationTokenProvider _cancellationTokenProvider; @@ -25,11 +29,20 @@ namespace Volo.Abp.Uow.MongoDB _unitOfWorkManager = unitOfWorkManager; _connectionStringResolver = connectionStringResolver; _cancellationTokenProvider = cancellationTokenProvider; + + Logger = NullLogger>.Instance; } [Obsolete("Use CreateDbContextAsync")] public TMongoDbContext GetDbContext() { + Logger.LogWarning( + "UnitOfWorkDbContextProvider.GetDbContext is deprecated. Use GetDbContextAsync instead! " + + "You are probably using LINQ (LINQ extensions) directly on a repository. In this case, use repository.GetQueryableAsync() method " + + "to obtain an IQueryable instance and use LINQ (LINQ extensions) on this object. " + ); + Logger.LogWarning(Environment.StackTrace.Truncate(2048)); + var unitOfWork = _unitOfWorkManager.Current; if (unitOfWork == null) { From 65c4f199637a6484320ab20185d92c1b7a9ec255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 25 Dec 2020 20:53:55 +0300 Subject: [PATCH 35/83] Convert to singleton for a better DI performance. --- .../Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs | 2 +- .../Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs | 2 +- .../Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs | 2 +- .../Volo.Abp.Threading/Volo/Abp/Linq/AsyncQueryableExecuter.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs index 061bc62018..d827b41101 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs @@ -6,7 +6,7 @@ using Volo.Abp.Uow; namespace Volo.Abp.AspNetCore.Uow { - public class AspNetCoreUnitOfWorkTransactionBehaviourProvider : IUnitOfWorkTransactionBehaviourProvider, ITransientDependency + public class AspNetCoreUnitOfWorkTransactionBehaviourProvider : IUnitOfWorkTransactionBehaviourProvider, ISingletonDependency { private readonly IHttpContextAccessor _httpContextAccessor; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs index 68ff261588..2a0400c578 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EfCoreAsyncQueryableProvider.cs @@ -11,7 +11,7 @@ using Volo.Abp.Linq; namespace Volo.Abp.EntityFrameworkCore { - public class EfCoreAsyncQueryableProvider : IAsyncQueryableProvider, ITransientDependency + public class EfCoreAsyncQueryableProvider : IAsyncQueryableProvider, ISingletonDependency { public bool CanExecute(IQueryable queryable) { diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs index a8dc34e83a..52c5edd1d3 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs @@ -12,7 +12,7 @@ using Volo.Abp.DynamicProxy; namespace Volo.Abp.MongoDB { - public class MongoDbAsyncQueryableProvider : IAsyncQueryableProvider, ITransientDependency + public class MongoDbAsyncQueryableProvider : IAsyncQueryableProvider, ISingletonDependency { public bool CanExecute(IQueryable queryable) { diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Linq/AsyncQueryableExecuter.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Linq/AsyncQueryableExecuter.cs index f5b3cf3a6d..b7ac83dc5f 100644 --- a/framework/src/Volo.Abp.Threading/Volo/Abp/Linq/AsyncQueryableExecuter.cs +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Linq/AsyncQueryableExecuter.cs @@ -8,7 +8,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Linq { - public class AsyncQueryableExecuter : IAsyncQueryableExecuter, ITransientDependency + public class AsyncQueryableExecuter : IAsyncQueryableExecuter, ISingletonDependency { protected IEnumerable Providers { get; } From 95b7b0693b3f55038843b599402b434233f7ef78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 25 Dec 2020 21:17:01 +0300 Subject: [PATCH 36/83] Extract AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions. --- ...eUnitOfWorkTransactionBehaviourProvider.cs | 19 +++++++++++++++---- ...WorkTransactionBehaviourProviderOptions.cs | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions.cs diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs index d827b41101..fd1d20d905 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs @@ -1,6 +1,7 @@ using System; using System.Net.Http; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Uow; @@ -9,6 +10,7 @@ namespace Volo.Abp.AspNetCore.Uow public class AspNetCoreUnitOfWorkTransactionBehaviourProvider : IUnitOfWorkTransactionBehaviourProvider, ISingletonDependency { private readonly IHttpContextAccessor _httpContextAccessor; + private readonly AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions _options; public virtual bool? IsTransactional { @@ -20,10 +22,16 @@ namespace Volo.Abp.AspNetCore.Uow return null; } - //IdentityServer endpoint (TODO: Better to move to the IDS module) - if (httpContext.Request.Path.Value?.StartsWith("/connect/", StringComparison.OrdinalIgnoreCase) == true) + var currentUrl = httpContext.Request.Path.Value; + if (currentUrl != null) { - return false; + foreach (var url in _options.NonTransactionalUrls) + { + if (currentUrl.StartsWith(url, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + } } return !string.Equals( @@ -33,9 +41,12 @@ namespace Volo.Abp.AspNetCore.Uow } } - public AspNetCoreUnitOfWorkTransactionBehaviourProvider(IHttpContextAccessor httpContextAccessor) + public AspNetCoreUnitOfWorkTransactionBehaviourProvider( + IHttpContextAccessor httpContextAccessor, + IOptions options) { _httpContextAccessor = httpContextAccessor; + _options = options.Value; } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions.cs new file mode 100644 index 0000000000..dd612a008d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Uow +{ + public class AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions + { + public List NonTransactionalUrls { get; } + + public AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions() + { + NonTransactionalUrls = new List + { + "/connect/" + }; + } + } +} From 03d68743413c02d2f01d9f96acb5fd0975610f58 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 28 Dec 2020 10:17:12 +0300 Subject: [PATCH 37/83] Fix SolutionModuleAdder.RemoveProjectByPostFix --- .../Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index 4eae8ace8f..acb723236b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -206,6 +206,12 @@ namespace Volo.Abp.Cli.ProjectModification { var srcPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), targetFolder); var projectFolderPath = Directory.GetDirectories(srcPath).FirstOrDefault(d=> d.EndsWith(postFix)); + + if(projectFolderPath == null) + { + return; + } + await SolutionFileModifier.RemoveProjectFromSolutionFileAsync(moduleSolutionFile, new DirectoryInfo(projectFolderPath).Name); if (Directory.Exists(projectFolderPath)) From cb7e65ccc751c47d63da9ce33008ae314d89a30b Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 28 Dec 2020 10:34:20 +0300 Subject: [PATCH 38/83] Remove commandLineArgs & workingDirectory from launchSettings.json --- framework/src/Volo.Abp.Cli/Properties/launchSettings.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.Cli/Properties/launchSettings.json b/framework/src/Volo.Abp.Cli/Properties/launchSettings.json index 6846f7adbd..e7f99eea04 100644 --- a/framework/src/Volo.Abp.Cli/Properties/launchSettings.json +++ b/framework/src/Volo.Abp.Cli/Properties/launchSettings.json @@ -1,9 +1,7 @@ { "profiles": { "Volo.Abp.Cli": { - "commandName": "Project", - "commandLineArgs": "bundle --skip-version-check", - "workingDirectory": "C:\\Github\\volo\\abp\\templates\\app-pro\\aspnet-core\\src\\MyCompanyName.MyProjectName.Blazor" + "commandName": "Project" } } } \ No newline at end of file From 5edd578eb789dbca74f6ab63b54283b1f348141e Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 28 Dec 2020 10:36:21 +0300 Subject: [PATCH 39/83] Delete launchSettings.json --- framework/src/Volo.Abp.Cli/Properties/launchSettings.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 framework/src/Volo.Abp.Cli/Properties/launchSettings.json diff --git a/framework/src/Volo.Abp.Cli/Properties/launchSettings.json b/framework/src/Volo.Abp.Cli/Properties/launchSettings.json deleted file mode 100644 index e7f99eea04..0000000000 --- a/framework/src/Volo.Abp.Cli/Properties/launchSettings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "profiles": { - "Volo.Abp.Cli": { - "commandName": "Project" - } - } -} \ No newline at end of file From f2641509c4b09b20f1a5da9a92026eff8afe288c Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 28 Dec 2020 14:17:32 +0300 Subject: [PATCH 40/83] Cli new command: change connection string by dbms --- .../Volo/Abp/Cli/Commands/NewCommand.cs | 25 +++++++++++++++++++ .../TemplateProjectBuildPipelineBuilder.cs | 11 ++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 3bd8aecbc1..3b2666695e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -150,6 +150,13 @@ namespace Volo.Abp.Cli.Commands Logger.LogInformation("Output folder: " + outputFolder); + if (connectionString == null && + databaseManagementSystem != DatabaseManagementSystem.NotSpecified && + databaseManagementSystem != DatabaseManagementSystem.SQLServer) + { + connectionString = GetNewConnectionStringByDbms(databaseManagementSystem, outputFolder); + } + commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command); var result = await TemplateProjectBuilder.BuildAsync( @@ -219,6 +226,24 @@ namespace Volo.Abp.Cli.Commands } } + private string GetNewConnectionStringByDbms(DatabaseManagementSystem databaseManagementSystem, string outputFolder) + { + switch (databaseManagementSystem) + { + case DatabaseManagementSystem.MySQL: + return "Server=localhost;Port=3306;Database=MyProjectName;Uid=root;Pwd=myPassword;"; + case DatabaseManagementSystem.PostgreSQL: + return "User ID=root;Password=myPassword;Host=localhost;Port=5432;Database=MyProjectName;Pooling=true;Min Pool Size=0;Max Pool Size=100;Connection Lifetime=0;"; + case DatabaseManagementSystem.Oracle: + case DatabaseManagementSystem.OracleDevart: + return "Data Source=MyProjectName;Integrated Security=yes;"; + case DatabaseManagementSystem.SQLite: + return $"Data Source={Path.Combine(outputFolder,"database\\MyProjectName.db")};Version=3;"; + default: + return null; + } + } + private void DeleteMigrationsIfNeeded(DatabaseProvider databaseProvider, DatabaseManagementSystem databaseManagementSystem, string outputFolder) { if (databaseManagementSystem == DatabaseManagementSystem.NotSpecified || databaseManagementSystem == DatabaseManagementSystem.SQLServer) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs index 9590001ea4..513c2b4198 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs @@ -17,6 +17,12 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building pipeline.Steps.Add(new ProjectReferenceReplaceStep()); pipeline.Steps.Add(new TemplateCodeDeleteStep()); + + if (context.BuildArgs.ConnectionString != null) + { + pipeline.Steps.Add(new ConnectionStringChangeStep()); + } + pipeline.Steps.Add(new SolutionRenameStep()); if (context.Template.Name == AppProTemplate.TemplateName || @@ -37,11 +43,6 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building pipeline.Steps.Add(new RemoveRootFolderStep()); } - if (context.BuildArgs.ConnectionString != null) - { - pipeline.Steps.Add(new ConnectionStringChangeStep()); - } - pipeline.Steps.Add(new CreateProjectResultZipStep()); return pipeline; From cfa005fcd7265b32a0d0a8af97c35001b0966c00 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 28 Dec 2020 14:18:25 +0300 Subject: [PATCH 41/83] Update NewCommand.cs --- .../src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 3b2666695e..c4942d04ab 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -234,7 +234,7 @@ namespace Volo.Abp.Cli.Commands return "Server=localhost;Port=3306;Database=MyProjectName;Uid=root;Pwd=myPassword;"; case DatabaseManagementSystem.PostgreSQL: return "User ID=root;Password=myPassword;Host=localhost;Port=5432;Database=MyProjectName;Pooling=true;Min Pool Size=0;Max Pool Size=100;Connection Lifetime=0;"; - case DatabaseManagementSystem.Oracle: + //case DatabaseManagementSystem.Oracle: case DatabaseManagementSystem.OracleDevart: return "Data Source=MyProjectName;Integrated Security=yes;"; case DatabaseManagementSystem.SQLite: From 55f8c1670c8faecc3bbbb1c9c4968e6f9baf71b0 Mon Sep 17 00:00:00 2001 From: Ilkay Ilknur Date: Mon, 28 Dec 2020 17:27:10 +0300 Subject: [PATCH 42/83] set lookup property display name to the text field. --- .../ObjectExtending/Modularity/EntityExtensionConfiguration.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 6733688a91..c2b56515b4 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 @@ -67,7 +67,8 @@ namespace Volo.Abp.ObjectExtending.Modularity lookupTextPropertyName, () => new ExtensionPropertyConfiguration(this, typeof(string), lookupTextPropertyName) ); - lookupTextPropertyInfo.DisplayName = propertyInfo.DisplayName ?? new FixedLocalizableString(propertyInfo.Name); + + lookupTextPropertyInfo.DisplayName = propertyInfo.DisplayName; } [NotNull] From 5c91b5af8ef95fc447f0ab35457de387eac53b1e Mon Sep 17 00:00:00 2001 From: Ilkay Ilknur Date: Mon, 28 Dec 2020 17:27:47 +0300 Subject: [PATCH 43/83] handle lookup property table header localization. --- .../ui-extensions.js | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 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 eacfecc867..e6061219b0 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) { @@ -149,7 +149,7 @@ return defaultValue; } - + function localizeEnumMember(property, enumMemberValue) { var enumType = property.config.type; var enumInfo = abp.objectExtensions.enums[enumType]; @@ -188,10 +188,28 @@ var propertyName = propertyNames[i]; var propertyConfig = objectConfig.properties[propertyName]; if (propertyConfig.ui.onTable.isVisible) { - tableProperties.push({ - name: propertyName, - config: propertyConfig - }); + if (propertyName.endsWith("_Text")) { + var lookupPropertyName = propertyName.replace("_Text", ""); + var lookupProperty = objectConfig.properties[lookupPropertyName]; + if (lookupProperty) { + tableProperties.push({ + name: propertyName, + config: propertyConfig, + lookupPropertyName: lookupPropertyName, + lookupPropertyDisplayName: lookupProperty.displayName + }); + } else { + tableProperties.push({ + name: propertyName, + config: propertyConfig, + }); + } + } else { + tableProperties.push({ + name: propertyName, + config: propertyConfig, + }); + } } } @@ -199,19 +217,23 @@ } function getValueFromRow(property, row) { - return row.extraProperties[property.name];; + return row.extraProperties[property.name]; } function convertPropertyToColumnConfig(property) { var columnConfig = { - title: localizeDisplayName(property.name, property.config.displayName), data: "extraProperties." + property.name, orderable: false }; + if (property.lookupPropertyName) { + columnConfig.title = localizeDisplayName(property.lookupPropertyName, property.lookupPropertyDisplayName); + } else { + columnConfig.title = localizeDisplayName(property.name, property.config.displayName); + } 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); } From 03551252f6c2864370373c5571309bffa31834fc Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 29 Dec 2020 15:55:34 +0800 Subject: [PATCH 44/83] DI support of AutoMapper --- .../Abp/AutoMapper/AbpAutoMapperModule.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs index 214872e371..89092faed4 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs @@ -13,7 +13,7 @@ namespace Volo.Abp.AutoMapper typeof(AbpObjectMappingModule), typeof(AbpObjectExtendingModule), typeof(AbpAuditingModule) - )] + )] public class AbpAutoMapperModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) @@ -21,16 +21,11 @@ namespace Volo.Abp.AutoMapper context.Services.AddAutoMapperObjectMapper(); var mapperAccessor = new MapperAccessor(); - context.Services.AddSingleton(_ => mapperAccessor); - context.Services.AddSingleton(_ => mapperAccessor); + context.Services.AddSingleton(_ => mapperAccessor); + context.Services.Add(new ServiceDescriptor(typeof(IMapperAccessor), CreateMappings, ServiceLifetime.Singleton)); } - public override void OnPreApplicationInitialization(ApplicationInitializationContext context) - { - CreateMappings(context.ServiceProvider); - } - - private void CreateMappings(IServiceProvider serviceProvider) + private IMapperAccessor CreateMappings(IServiceProvider serviceProvider) { using (var scope = serviceProvider.CreateScope()) { @@ -48,7 +43,7 @@ namespace Volo.Abp.AutoMapper { foreach (var profileType in options.ValidatingProfiles) { - config.AssertConfigurationIsValid(((Profile)Activator.CreateInstance(profileType)).ProfileName); + config.AssertConfigurationIsValid(((Profile) Activator.CreateInstance(profileType)).ProfileName); } } @@ -59,7 +54,10 @@ namespace Volo.Abp.AutoMapper ValidateAll(mapperConfiguration); - scope.ServiceProvider.GetRequiredService().Mapper = mapperConfiguration.CreateMapper(); + var mapperAccessor = scope.ServiceProvider.GetRequiredService(); + mapperAccessor.Mapper = new Mapper(mapperConfiguration, serviceProvider.GetService); + + return mapperAccessor; } } } From 364732114c3e798f69d0af1bbadcfd136a474962 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 29 Dec 2020 16:46:53 +0800 Subject: [PATCH 45/83] Add AbpAutoMapperConventionalRegistrar --- .../AbpAutoMapperConventionalRegistrar.cs | 34 +++++++++++++++++++ .../Abp/AutoMapper/AbpAutoMapperModule.cs | 5 +++ 2 files changed, 39 insertions(+) create mode 100644 framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs new file mode 100644 index 0000000000..f6af2f566f --- /dev/null +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using AutoMapper; +using AutoMapper.Internal; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AutoMapper +{ + public class AbpAutoMapperConventionalRegistrar : ConventionalRegistrarBase + { + protected readonly Type[] OpenTypes = { + typeof(IValueResolver<,,>), + typeof(IMemberValueResolver<,,,>), + typeof(ITypeConverter<,>), + typeof(IValueConverter<,>), + typeof(IMappingAction<,>) + }; + + public override void AddType(IServiceCollection services, Type type) + { + if (IsConventionalRegistrationDisabled(type)) + { + return; + } + + if (OpenTypes.Any(type.ImplementsGenericInterface)) + { + services.TryAddTransient(type); + } + } + } +} diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs index 89092faed4..479173b72d 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs @@ -16,6 +16,11 @@ namespace Volo.Abp.AutoMapper )] public class AbpAutoMapperModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddConventionalRegistrar(new AbpAutoMapperConventionalRegistrar()); + } + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAutoMapperObjectMapper(); From 82888df9bcab287246e37fc871776a5bce56d3c6 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 29 Dec 2020 16:49:03 +0800 Subject: [PATCH 46/83] Update AbpAutoMapperConventionalRegistrar --- .../Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs index f6af2f566f..86fc494676 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.AutoMapper return; } - if (OpenTypes.Any(type.ImplementsGenericInterface)) + if (type.IsClass && !type.IsAbstract && OpenTypes.Any(type.ImplementsGenericInterface)) { services.TryAddTransient(type); } From 91595ee0ca0816654ec780c46bae9ba2ef055887 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 29 Dec 2020 17:51:57 +0800 Subject: [PATCH 47/83] add unit tests --- .../AutoMapper_MapperAction_Tests.cs | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_MapperAction_Tests.cs diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_MapperAction_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_MapperAction_Tests.cs new file mode 100644 index 0000000000..aa1324927a --- /dev/null +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_MapperAction_Tests.cs @@ -0,0 +1,87 @@ +using AutoMapper; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Testing; +using Xunit; +using IObjectMapper = Volo.Abp.ObjectMapping.IObjectMapper; + +namespace Volo.Abp.AutoMapper +{ + public class AutoMapper_MapperAction_Tests : AbpIntegratedTest + { + private readonly IObjectMapper _objectMapper; + + public AutoMapper_MapperAction_Tests() + { + _objectMapper = ServiceProvider.GetRequiredService(); + } + + [Fact] + public void Should_Name_DIMappingAction() + { + var mapperActionEntity = new MapperActionModel {Name = "MapperActionEntity"}; + _objectMapper.Map(mapperActionEntity) + .Name.ShouldBe(nameof(DIMappingAction)); + } + + [Fact] + public void Should_Name_NotDIMappingAction() + { + var mapperActionEntity = new MapperActionModel2 {Name = "MapperActionEntity"}; + _objectMapper.Map(mapperActionEntity) + .Name.ShouldBe(nameof(NotDIMapperAction)); + } + + public class MapperActionModel + { + public string Name { get; set; } + } + + public class MapperActionModel2 + { + public string Name { get; set; } + } + + public class MapperActionProfile : Profile + { + public MapperActionProfile() + { + CreateMap().AfterMap(); + CreateMap().AfterMap(); + } + } + + public class DIMappingAction : IMappingAction + { + private readonly MapperActionService _mapperActionService; + + public DIMappingAction(MapperActionService mapperActionService) + { + _mapperActionService = mapperActionService; + } + + public void Process(MapperActionModel source, MapperActionModel2 destination, ResolutionContext context) + { + destination.Name = _mapperActionService.GetName(); + } + } + + public class NotDIMapperAction : IMappingAction + { + public void Process(MapperActionModel2 source, MapperActionModel destination, + ResolutionContext context) + { + destination.Name = nameof(NotDIMapperAction); + } + } + + public class MapperActionService : ITransientDependency + { + public string GetName() + { + return nameof(DIMappingAction); + } + } + } +} From b6cb2860e3832ae884f87f88d4b56979266915e7 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 30 Dec 2020 20:50:11 +0800 Subject: [PATCH 48/83] Fix MapperAccessor problem. --- .../Abp/AutoMapper/AbpAutoMapperModule.cs | 15 ++- .../AutoMapper_Dependency_Injection_Tests.cs | 111 ++++++++++++++++++ .../AutoMapper_MapperAction_Tests.cs | 87 -------------- 3 files changed, 118 insertions(+), 95 deletions(-) create mode 100644 framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_Dependency_Injection_Tests.cs delete mode 100644 framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_MapperAction_Tests.cs diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs index 479173b72d..25707e3899 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs @@ -25,12 +25,11 @@ namespace Volo.Abp.AutoMapper { context.Services.AddAutoMapperObjectMapper(); - var mapperAccessor = new MapperAccessor(); - context.Services.AddSingleton(_ => mapperAccessor); - context.Services.Add(new ServiceDescriptor(typeof(IMapperAccessor), CreateMappings, ServiceLifetime.Singleton)); + context.Services.AddSingleton(provider => CreateMappings(provider)); + context.Services.AddSingleton(provider => provider.GetRequiredService()); } - private IMapperAccessor CreateMappings(IServiceProvider serviceProvider) + private MapperAccessor CreateMappings(IServiceProvider serviceProvider) { using (var scope = serviceProvider.CreateScope()) { @@ -59,10 +58,10 @@ namespace Volo.Abp.AutoMapper ValidateAll(mapperConfiguration); - var mapperAccessor = scope.ServiceProvider.GetRequiredService(); - mapperAccessor.Mapper = new Mapper(mapperConfiguration, serviceProvider.GetService); - - return mapperAccessor; + return new MapperAccessor + { + Mapper = new Mapper(mapperConfiguration, serviceProvider.GetService) + }; } } } diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_Dependency_Injection_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_Dependency_Injection_Tests.cs new file mode 100644 index 0000000000..891ef0ddbb --- /dev/null +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_Dependency_Injection_Tests.cs @@ -0,0 +1,111 @@ +using AutoMapper; +using Shouldly; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Testing; +using Xunit; +using IObjectMapper = Volo.Abp.ObjectMapping.IObjectMapper; + +namespace Volo.Abp.AutoMapper +{ + public class AutoMapper_Dependency_Injection_Tests : AbpIntegratedTest + { + private readonly IObjectMapper _objectMapper; + + public AutoMapper_Dependency_Injection_Tests() + { + _objectMapper = GetRequiredService(); + } + + [Fact] + public void Should_Registered_AutoMapper_Service() + { + GetService>().ShouldBeNull(); + GetService>().ShouldBeNull(); + GetService>().ShouldBeNull(); + GetService>().ShouldBeNull(); + GetService>().ShouldBeNull(); + } + + [Fact] + public void Custom_MappingAction_Test() + { + var sourceModel = new SourceModel + { + Name = "Source" + }; + + _objectMapper.Map(sourceModel).Name.ShouldBe(GetRequiredService().Name); + } + + public class SourceModel + { + public string Name { get; set; } + } + + public class DestModel + { + public string Name { get; set; } + } + + public class TestService : + IValueResolver, + IMemberValueResolver, + ITypeConverter, + IValueConverter, + IMappingAction + { + public string Resolve(string source, string destination, string destMember, ResolutionContext context) + { + return source; + } + + public string Resolve(string source, string destination, string sourceMember, string destMember, ResolutionContext context) + { + return source; + } + + public string Convert(string source, string destination, ResolutionContext context) + { + return source; + } + + public string Convert(string sourceMember, ResolutionContext context) + { + return sourceMember; + } + + public void Process(string source, string destination, ResolutionContext context) + { + + } + } + + public class MapperActionProfile : Profile + { + public MapperActionProfile() + { + CreateMap().AfterMap(); + } + } + + public class CustomMappingAction : IMappingAction + { + private readonly TestNameService _testNameService; + + public CustomMappingAction(TestNameService testNameService) + { + _testNameService = testNameService; + } + + public void Process(SourceModel source, DestModel destination, ResolutionContext context) + { + destination.Name = _testNameService.Name; + } + } + + public class TestNameService : ITransientDependency + { + public string Name => nameof(TestNameService); + } + } +} diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_MapperAction_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_MapperAction_Tests.cs deleted file mode 100644 index aa1324927a..0000000000 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_MapperAction_Tests.cs +++ /dev/null @@ -1,87 +0,0 @@ -using AutoMapper; -using Microsoft.Extensions.DependencyInjection; -using Shouldly; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Testing; -using Xunit; -using IObjectMapper = Volo.Abp.ObjectMapping.IObjectMapper; - -namespace Volo.Abp.AutoMapper -{ - public class AutoMapper_MapperAction_Tests : AbpIntegratedTest - { - private readonly IObjectMapper _objectMapper; - - public AutoMapper_MapperAction_Tests() - { - _objectMapper = ServiceProvider.GetRequiredService(); - } - - [Fact] - public void Should_Name_DIMappingAction() - { - var mapperActionEntity = new MapperActionModel {Name = "MapperActionEntity"}; - _objectMapper.Map(mapperActionEntity) - .Name.ShouldBe(nameof(DIMappingAction)); - } - - [Fact] - public void Should_Name_NotDIMappingAction() - { - var mapperActionEntity = new MapperActionModel2 {Name = "MapperActionEntity"}; - _objectMapper.Map(mapperActionEntity) - .Name.ShouldBe(nameof(NotDIMapperAction)); - } - - public class MapperActionModel - { - public string Name { get; set; } - } - - public class MapperActionModel2 - { - public string Name { get; set; } - } - - public class MapperActionProfile : Profile - { - public MapperActionProfile() - { - CreateMap().AfterMap(); - CreateMap().AfterMap(); - } - } - - public class DIMappingAction : IMappingAction - { - private readonly MapperActionService _mapperActionService; - - public DIMappingAction(MapperActionService mapperActionService) - { - _mapperActionService = mapperActionService; - } - - public void Process(MapperActionModel source, MapperActionModel2 destination, ResolutionContext context) - { - destination.Name = _mapperActionService.GetName(); - } - } - - public class NotDIMapperAction : IMappingAction - { - public void Process(MapperActionModel2 source, MapperActionModel destination, - ResolutionContext context) - { - destination.Name = nameof(NotDIMapperAction); - } - } - - public class MapperActionService : ITransientDependency - { - public string GetName() - { - return nameof(DIMappingAction); - } - } - } -} From b8bc6973110c9bac81c05893cc456caef7670f88 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 30 Dec 2020 21:32:58 +0800 Subject: [PATCH 49/83] Fix Should_Registered_AutoMapper_Service test method. --- .../AutoMapper_Dependency_Injection_Tests.cs | 59 ++----------------- 1 file changed, 5 insertions(+), 54 deletions(-) diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_Dependency_Injection_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_Dependency_Injection_Tests.cs index 891ef0ddbb..56c5e6f061 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_Dependency_Injection_Tests.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapper_Dependency_Injection_Tests.cs @@ -19,11 +19,7 @@ namespace Volo.Abp.AutoMapper [Fact] public void Should_Registered_AutoMapper_Service() { - GetService>().ShouldBeNull(); - GetService>().ShouldBeNull(); - GetService>().ShouldBeNull(); - GetService>().ShouldBeNull(); - GetService>().ShouldBeNull(); + GetService().ShouldNotBeNull(); } [Fact] @@ -34,7 +30,7 @@ namespace Volo.Abp.AutoMapper Name = "Source" }; - _objectMapper.Map(sourceModel).Name.ShouldBe(GetRequiredService().Name); + _objectMapper.Map(sourceModel).Name.ShouldBe(nameof(CustomMappingActionService)); } public class SourceModel @@ -47,65 +43,20 @@ namespace Volo.Abp.AutoMapper public string Name { get; set; } } - public class TestService : - IValueResolver, - IMemberValueResolver, - ITypeConverter, - IValueConverter, - IMappingAction - { - public string Resolve(string source, string destination, string destMember, ResolutionContext context) - { - return source; - } - - public string Resolve(string source, string destination, string sourceMember, string destMember, ResolutionContext context) - { - return source; - } - - public string Convert(string source, string destination, ResolutionContext context) - { - return source; - } - - public string Convert(string sourceMember, ResolutionContext context) - { - return sourceMember; - } - - public void Process(string source, string destination, ResolutionContext context) - { - - } - } - public class MapperActionProfile : Profile { public MapperActionProfile() { - CreateMap().AfterMap(); + CreateMap().AfterMap(); } } - public class CustomMappingAction : IMappingAction + public class CustomMappingActionService : IMappingAction { - private readonly TestNameService _testNameService; - - public CustomMappingAction(TestNameService testNameService) - { - _testNameService = testNameService; - } - public void Process(SourceModel source, DestModel destination, ResolutionContext context) { - destination.Name = _testNameService.Name; + destination.Name = nameof(CustomMappingActionService); } } - - public class TestNameService : ITransientDependency - { - public string Name => nameof(TestNameService); - } } } From 1ff40d4bd2ceecc4d7f9607ce28de5509b55ac9d Mon Sep 17 00:00:00 2001 From: GameBelial <243387971@qq.com> Date: Thu, 31 Dec 2020 13:11:57 +0800 Subject: [PATCH 50/83] To solve the issue of Issue-6819, for SQL Server, the connection string does not enable the MultipleActiveResultSets=true feature by default. --- .../MyCompanyName.MyProjectName.DbMigrator/appsettings.json | 2 +- .../MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json | 2 +- .../appsettings.json | 2 +- .../appsettings.json | 2 +- .../src/MyCompanyName.MyProjectName.Web/appsettings.json | 2 +- .../MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json | 4 ++-- .../appsettings.json | 2 +- .../MyCompanyName.MyProjectName.Web.Unified/appsettings.json | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json index 1d9beacd54..b9ba4298dd 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True" }, "IdentityServer": { "Clients": { diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json index 6c64a7b397..12bd4f78bb 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json @@ -3,7 +3,7 @@ "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307" }, "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/appsettings.json index 1051a8576c..73d80aeec4 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/appsettings.json @@ -5,7 +5,7 @@ "RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307" }, "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True" }, "AuthServer": { "Authority": "https://localhost:44305", diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json index c7101f92ed..0e667e5d73 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json @@ -5,7 +5,7 @@ "RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307" }, "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/appsettings.json index 8084875aa5..9c81e66699 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/appsettings.json @@ -3,7 +3,7 @@ "SelfUrl": "https://localhost:44303" }, "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True" }, "AuthServer": { "Authority": "https://localhost:44303", diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json index d80fc69b59..b35a5997cf 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json @@ -3,8 +3,8 @@ "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,http://localhost:44307,https://localhost:44307" }, "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Main;Trusted_Connection=True;MultipleActiveResultSets=true", - "MyProjectName": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Module;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Main;Trusted_Connection=True", + "MyProjectName": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Module;Trusted_Connection=True" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json index dd966995a3..29608e57a4 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json @@ -5,7 +5,7 @@ }, "AppSelfUrl": "https://localhost:44301/", "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Main;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Main;Trusted_Connection=True" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/appsettings.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/appsettings.json index e081a57a67..f90c5b2d28 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/appsettings.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/appsettings.json @@ -1,5 +1,5 @@ { "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Unified;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Unified;Trusted_Connection=True" } } \ No newline at end of file From 00a71897b43e01bfb8745e937b53ec69be8e36f2 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Thu, 31 Dec 2020 09:39:48 +0300 Subject: [PATCH 51/83] Fix SolutionModuleAdder.RemoveProjectByPostFix --- .../Cli/ProjectModification/SolutionModuleAdder.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index 4eae8ace8f..2dc7febeac 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -205,14 +205,25 @@ namespace Volo.Abp.Cli.ProjectModification string postFix) { var srcPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), targetFolder); + + if (!Directory.Exists(srcPath)) + { + return; + } + var projectFolderPath = Directory.GetDirectories(srcPath).FirstOrDefault(d=> d.EndsWith(postFix)); + + if (projectFolderPath == null) + { + return; + } + await SolutionFileModifier.RemoveProjectFromSolutionFileAsync(moduleSolutionFile, new DirectoryInfo(projectFolderPath).Name); if (Directory.Exists(projectFolderPath)) { Directory.Delete(projectFolderPath, true); } - } private async Task ChangeDomainTestReferenceToMongoDB(ModuleWithMastersInfo module, string moduleSolutionFile) From 912a24702653845632dc9f42ce5930b801ab0f78 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 31 Dec 2020 16:22:40 +0800 Subject: [PATCH 52/83] Remove permission Grants when role is delete --- .../Identity/RoleDeletedEventHandler.cs | 26 +++++++++++++++++++ .../IPermissionManager.cs | 4 ++- .../PermissionManagement/PermissionManager.cs | 12 ++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs new file mode 100644 index 0000000000..806a37de7c --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; +using Volo.Abp.Identity; + +namespace Volo.Abp.PermissionManagement.Identity +{ + public class RoleDeletedEventHandler : + ILocalEventHandler>, + ITransientDependency + { + protected IPermissionManager PermissionManager { get; } + + public RoleDeletedEventHandler(IPermissionManager permissionManager) + { + PermissionManager = permissionManager; + } + + public virtual async Task HandleEventAsync(EntityDeletedEventData eventData) + { + await PermissionManager.DeleteAsync(RolePermissionValueProvider.ProviderName, eventData.Entity.Name); + } + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs index 26310a12fe..70bb83a7d0 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs @@ -15,5 +15,7 @@ namespace Volo.Abp.PermissionManagement Task SetAsync(string permissionName, string providerName, string providerKey, bool isGranted); Task UpdateProviderKeyAsync(PermissionGrant permissionGrant, string providerKey); + + Task DeleteAsync(string providerName, string providerKey); } -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs index 9a2a89e340..fc8da0c6c5 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs @@ -111,6 +111,16 @@ namespace Volo.Abp.PermissionManagement return await PermissionGrantRepository.UpdateAsync(permissionGrant); } + public virtual async Task DeleteAsync(string providerName, string providerKey) + { + var permissionGrants = await PermissionGrantRepository.GetListAsync(providerName, providerKey); + //TODO: Use DeleteManyAsync method + foreach (var permissionGrant in permissionGrants) + { + await PermissionGrantRepository.DeleteAsync(permissionGrant); + } + } + protected virtual async Task GetInternalAsync(PermissionDefinition permission, string providerName, string providerKey) { var result = new PermissionWithGrantedProviders(permission.Name, false); @@ -143,4 +153,4 @@ namespace Volo.Abp.PermissionManagement return result; } } -} \ No newline at end of file +} From 91cb7d5e57f9678f3c6935a7bba9f6a3ad316f13 Mon Sep 17 00:00:00 2001 From: enisn Date: Thu, 31 Dec 2020 17:22:40 +0300 Subject: [PATCH 53/83] CmsKit - Add Feature check to PermissionDefinitionProvider --- .../CmsKitAdminPermissionDefinitionProvider.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs index 2cb6a53b58..507b1c276f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs @@ -1,5 +1,7 @@ using Volo.Abp.Authorization.Permissions; +using Volo.Abp.GlobalFeatures; using Volo.Abp.Localization; +using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Localization; namespace Volo.CmsKit.Permissions @@ -10,11 +12,13 @@ namespace Volo.CmsKit.Permissions { var cmsGroup = context.GetGroupOrNull(CmsKitAdminPermissions.GroupName) ?? context.AddGroup(CmsKitAdminPermissions.GroupName, L("Permission:CmsKit")); - cmsGroup - .AddPermission(CmsKitAdminPermissions.Tags.Default, L("Permission:TagManagement")) - .AddChild(CmsKitAdminPermissions.Tags.Create, L("Permission:TagManagement.Create")) - .AddChild(CmsKitAdminPermissions.Tags.Update, L("Permission:TagManagement.Update")) - .AddChild(CmsKitAdminPermissions.Tags.Delete, L("Permission:TagManagement.Delete")); + if (GlobalFeatureManager.Instance.IsEnabled()) + { + var tagGroup = cmsGroup.AddPermission(CmsKitAdminPermissions.Tags.Default, L("Permission:TagManagement")); + tagGroup.AddChild(CmsKitAdminPermissions.Tags.Create, L("Permission:TagManagement.Create")); + tagGroup.AddChild(CmsKitAdminPermissions.Tags.Update, L("Permission:TagManagement.Update")); + tagGroup.AddChild(CmsKitAdminPermissions.Tags.Delete, L("Permission:TagManagement.Delete")); + } } private static LocalizableString L(string name) From 99f4ab7e9de73db0570236cf4dac7736912a8442 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 31 Dec 2020 22:48:34 +0800 Subject: [PATCH 54/83] Update contribution document. --- docs/en/Contribution/Index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Contribution/Index.md b/docs/en/Contribution/Index.md index 07dc73ab24..d2525ae191 100644 --- a/docs/en/Contribution/Index.md +++ b/docs/en/Contribution/Index.md @@ -10,7 +10,7 @@ If you want to write **articles** or **how to guides** related to the ABP Framew You can always send pull requests to the GitHub repository. -- Clone the [ABP repository](https://github.com/abpframework/abp/) from GitHub. +- [Fork](https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/fork-a-repo) the [ABP repository](https://github.com/abpframework/abp/) from GitHub. - Build the repository using the `/build/build-all.ps1 -f` for one time. - Make the necessary changes, including unit/integration tests. - Send a pull request. From 33392af88cd55583682e362aeb8509c7f42d4a09 Mon Sep 17 00:00:00 2001 From: hajuuk Date: Fri, 1 Jan 2021 18:38:55 +1100 Subject: [PATCH 55/83] Update Emailing.md Spelling mistakes --- docs/en/Emailing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/Emailing.md b/docs/en/Emailing.md index aa341a3898..a98874165d 100644 --- a/docs/en/Emailing.md +++ b/docs/en/Emailing.md @@ -223,7 +223,7 @@ Pathes of the templates in the virtual file system are shown below: * `/Volo/Abp/Emailing/Templates/Layout.tpl` * `/Volo/Abp/Emailing/Templates/Message.tpl` -If you add files to the same localization in the virtual file system, your files will override them. +If you add files to the same location in the virtual file system, your files will override them. Templates are inline localized, that means you can take the power of the [localization system](Localization.md) to make your templates multi-cultural. @@ -247,4 +247,4 @@ So, don't confuse if you don't receive emails on DEBUG mode. Emails will be sent ## See Also -* [MailKit integration for sending emails](MailKit.md) \ No newline at end of file +* [MailKit integration for sending emails](MailKit.md) From 7a3756bdfc23e9bf6a096f8223a30fe368e71ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 1 Jan 2021 13:33:01 +0300 Subject: [PATCH 56/83] Moved angular extensibility docs to open source. --- .../Customizing-Application-Modules-Guide.md | 43 +- .../Angular/Data-Table-Column-Extensions.md | 327 +++++++++++++ docs/en/UI/Angular/Dynamic-Form-Extensions.md | 325 +++++++++++++ .../en/UI/Angular/Entity-Action-Extensions.md | 442 ++++++++++++++++++ .../user-action-extension-click-me-ng.png | Bin 0 -> 142395 bytes ...-prop-extension-date-of-birth-field-ng.png | Bin 0 -> 154453 bytes .../user-prop-extension-name-column-ng.png | Bin 0 -> 82388 bytes 7 files changed, 1133 insertions(+), 4 deletions(-) create mode 100644 docs/en/UI/Angular/Data-Table-Column-Extensions.md create mode 100644 docs/en/UI/Angular/Dynamic-Form-Extensions.md create mode 100644 docs/en/UI/Angular/Entity-Action-Extensions.md create mode 100644 docs/en/UI/Angular/images/user-action-extension-click-me-ng.png create mode 100644 docs/en/UI/Angular/images/user-prop-extension-date-of-birth-field-ng.png create mode 100644 docs/en/UI/Angular/images/user-prop-extension-name-column-ng.png diff --git a/docs/en/Customizing-Application-Modules-Guide.md b/docs/en/Customizing-Application-Modules-Guide.md index d184d82906..da18d04d40 100644 --- a/docs/en/Customizing-Application-Modules-Guide.md +++ b/docs/en/Customizing-Application-Modules-Guide.md @@ -43,17 +43,52 @@ In any case, you can create a **separate solution** for the desired module and d #### Publishing the Customized Module as Packages -One alternative scenario could be re-packaging the module source code (as NuGet/NPM packages) and using as package references. You can use a local private NuGet/NPM server for your company. +One alternative scenario could be re-packaging the module source code (as NuGet/NPM packages) and using as package references. You can use a local private NuGet/NPM server for your company, for example. ## Module Customization / Extending Approaches -This section suggests some approaches if you decided to use pre-built application modules as NuGet/NPM package references. The following documents explain how to customize/extend existing modules in different ways: +This section suggests some approaches if you decided to use pre-built application modules as NuGet/NPM package references. The following documents explain how to customize/extend existing modules in different ways. + +### Module Entity Extension System + +Module entity extension system is the **main and high level extension system** that allows you to **define new properties** for existing entities of the depended modules. It automatically **adds properties to the entity, database, HTTP API and the user interface** in a single point. + +See the [Module Entity Extensions document](Module-Entity-Extensions.md) to learn how to use it. + +### Extending Entities + +If you only need to get/set extra data on an existing entity, follow the [Extending Entities](Customizing-Application-Modules-Extending-Entities.md) document. + +### Overriding Services/Components + +In addition to the extensibility systems, you can partially or completely override any service or user interface page/component. -* [Extending Entities](Customizing-Application-Modules-Extending-Entities.md) * [Overriding Services](Customizing-Application-Modules-Overriding-Services.md) * [Overriding the User Interface](Customizing-Application-Modules-Overriding-User-Interface.md) -### See Also +### Additional UI Extensibility Systems + +There are some low level systems that you can control entity actions, table columns and page toolbar of a page defined by a module. + +#### Entity Actions + +Entity action extension system allows you to add a new action to the action menu for an entity on the user interface; + +* [Entity Action Extensions for ASP.NET Core UI](UI/AspNetCore/Entity-Action-Extensions.md) +* [Entity Action Extensions for Angular](UI/Angular/Entity-Action-Extensions.md) + +#### Data Table Column Extensions + +Data table column extension system allows you to add a new column in the data table on the user interface; + +* [Data Table Column Extensions for ASP.NET Core UI](UI/AspNetCore/Data-Table-Column-Extensions.md) +* [Data Table Column Extensions for Angular](UI/Angular/Data-Table-Column-Extensions.md) + +#### Others + +* [Dynamic Form Extensions for Angular](UI/Angular/Dynamic-Form-Extensions.md) + +## See Also Also, see the following documents: diff --git a/docs/en/UI/Angular/Data-Table-Column-Extensions.md b/docs/en/UI/Angular/Data-Table-Column-Extensions.md new file mode 100644 index 0000000000..cd2df5cf4f --- /dev/null +++ b/docs/en/UI/Angular/Data-Table-Column-Extensions.md @@ -0,0 +1,327 @@ +# Data Table Column (or Entity Prop) Extensions for Angular UI + + +## Introduction + +Entity prop extension system allows you to add a new column to the data table for an entity or change/remove an already existing one. A "Name" column was added to the user management page below: + +![Entity Prop Extension Example: "Name" Column](images/user-prop-extension-name-column-ng.png) + +You will have access to the current entity in your code and display its value, make the column sortable, perform visibility checks, and more. You can also render custom HTML in table cells. + +## How to Set Up + +In this example, we will add a "Name" column and display the value of the `name` field in the user management page of the [Identity Module](../../Modules/Identity.md). + +### Step 1. Create Entity Prop Contributors + +The following code prepares a constant named `identityEntityPropContributors`, ready to be imported and used in your root module: + +```js +// entity-prop-contributors.ts + +import { EntityProp, EntityPropList, ePropType } from '@abp/ng.theme.shared/extensions'; +import { IdentityEntityPropContributors, IdentityUserDto } from '@volo/abp.ng.identity'; + +const nameProp = new EntityProp({ + type: ePropType.String, + name: 'name', + displayName: 'AbpIdentity::Name', + sortable: true, + columnWidth: 250, +}); + +export function namePropContributor(propList: EntityPropList) { + propList.addAfter( + nameProp, + 'userName', + (value, name) => value.name === name, + ); +} + +export const identityEntityPropContributors: IdentityEntityPropContributors = { + 'Identity.UsersComponent': [namePropContributor], +}; + +``` + +The list of props, conveniently named as `propList`, is a **doubly linked list**. That is why we have used the `addAfter` method, which adds a node with given value after the first node that has the previous value. You may find [all available methods here](../Common/Utils/Linked-List.md). + +> **Important Note 1:** AoT compilation does not support function calls in decorator metadata. This is why we have defined `namePropContributor` as an exported function declaration here. Please do not forget exporting your contributor callbacks and forget about lambda functions (a.k.a. arrow functions). Please refer to [AoT metadata errors](https://angular.io/guide/aot-metadata-errors#function-calls-not-supported) for details. + +> **Important Note 2:** Please use one of the following if Ivy is not enabled in your project. Otherwise, you will get an "Expression form not supported." error. + +```js +export const identityEntityPropContributors: IdentityEntityPropContributors = { + 'Identity.UsersComponent': [ namePropContributor ], +}; + +/* OR */ + +const identityContributors: IdentityEntityPropContributors = {}; +identityContributors[eIdentityComponents.Users] = [ namePropContributor ]; +export const identityEntityPropContributors = identityContributors; +``` + +### Step 2. Import and Use Entity Prop Contributors + +Import `identityEntityPropContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below: + +```js +import { identityEntityPropContributors } from './entity-prop-contributors'; + +const routes: Routes = [ + { + path: '', + component: DynamicLayoutComponent, + children: [ + { + path: 'identity', + loadChildren: () => + import('@volo/abp.ng.identity').then(m => + m.IdentityModule.forLazy({ + entityPropContributors: identityEntityPropContributors, + }), + ), + }, + // other child routes + ], + // other routes + } +]; +``` + +That is it, `nameProp` entity prop will be added, and you will see the "Name" column next to the usernames on the grid in the users page (`UsersComponent`) of the `IdentityModule`. + +## How to Render Custom HTML in Cells + +You can use the `valueResolver` to render an HTML string in the table. Imagine we want to show a red times icon (❌) next to unconfirmed emails and phones, instead of showing a green check icon next to confirmed emails and phones. The contributors below would do that for you. + +```js +// entity-prop-contributors.ts + +import { EntityProp, EntityPropList, ePropType } from '@abp/ng.theme.shared/extensions'; +import { IdentityUserDto } from '@volo/abp.ng.identity'; +import { IdentityEntityPropContributors } from '@volo/abp.ng.identity/config'; + +export function emailPropContributor(propList: EntityPropList) { + const index = propList.indexOf('email', (value, name) => value.name === name); + const droppedNode = propList.dropByIndex(index); + const emailProp = new EntityProp({ + ...droppedNode.value, + valueResolver: data => { + const { email, emailConfirmed } = data.record; + const icon = email && !emailConfirmed ? `` : ''; + + return of((email || '') + icon); // should return an observable + }, + }); + + propList.addByIndex(emailProp, index); +} + +export function phonePropContributor(propList: EntityPropList) { + const index = propList.indexOf('phoneNumber', (value, name) => value.name === name); + const droppedNode = propList.dropByIndex(index); + const phoneProp = new EntityProp({ + ...droppedNode.value, + valueResolver: data => { + const { phoneNumber, phoneNumberConfirmed } = data.record; + const icon = + phoneNumber && !phoneNumberConfirmed ? `` : ''; + + return of((phoneNumber || '') + icon); // should return an observable + }, + }); + + propList.addByIndex(phoneProp, index); +} + +export const identityEntityPropContributors: IdentityEntityPropContributors = { + 'Identity.UsersComponent': [emailPropContributor, phonePropContributor], +}; + +``` + +> The `valueResolver` method should return an observable. You can wrap your return values with `of` from RxJS for that. + +## Object Extensions + +Extra properties defined on an existing entity will be included in the table based on their configuration. The values will also be mapped to and from `extraProperties` automatically. They are available when defining custom contributors, so you can drop, modify, or reorder them. The `isExtra` identifier will be set to `true` for these properties and will define this automatic behavior. + +## API + +### PropData\ + +`PropData` is the shape of the parameter passed to all callbacks or predicates in an `EntityProp`. + +It has the following properties: + +- **record** is the row data, i.e. current value rendered in the table. + + ```js + { + type: ePropType.String, + name: 'name', + valueResolver: data => { + const name = data.record.name || ''; + return of(name.toUpperCase()); + }, + } + ``` + +- **index** is the table index where the record is at. + +- **getInjected** is the equivalent of [Injector.get](https://angular.io/api/core/Injector#get). You can use it to reach injected dependencies of `ExtensibleTableComponent`, including, but not limited to, its parent component. + + ```js + { + type: ePropType.String, + name: 'name', + valueResolver: data => { + const restService = data.getInjected(RestService); + const usersComponent = data.getInjected(UsersComponent); + + // Use restService and usersComponent public props and methods here + }, + } + ``` + +### PropCallback\ + +`PropCallback` is the type of the callback function that can be passed to an `EntityProp` as `prop` parameter. A prop callback gets a single parameter, the `PropData`. The return type may be anything, including `void`. Here is a simplified representation: + +```js +type PropCallback = (data?: PropData) => R; +``` + +### PropPredicate\ + +`PropPredicate` is the type of the predicate function that can be passed to an `EntityProp` as `visible` parameter. A prop predicate gets a single parameter, the `PropData`. The return type must be `boolean`. Here is a simplified representation: + +```js +type PropPredicate = (data?: PropData) => boolean; +``` + +### EntityPropOptions\ + +`EntityPropOptions` is the type that defines required and optional properties you have to pass in order to create an entity prop. + +Its type definition is as follows: + +```js +type EntityPropOptions = { + type: ePropType; + name: string; + displayName?: string; + valueResolver?: PropCallback>; + sortable?: boolean; + columnWidth?: number; + permission?: string; + visible?: PropPredicate; +}; +``` + +As you see, passing `type` and `name` is enough to create an entity prop. Here is what each property is good for: + +- **type** is the type of the prop value. It is used for custom rendering in the table. (_required_) +- **name** is the property name (or key) which will be used to read the value of the prop. (_required_) +- **displayName** is the name of the property which will be localized and shown as column header. (_default:_ `options.name`) +- **valueResolver** is a callback that is called when the cell is rendered. It must return an observable. (_default:_ `data => of(data.record[options.name])`) +- **sortable** defines if the table is sortable based on this entity prop. Sort icons are shown based on it. (_default:_ `false`) +- **columnWidth** defines a minimum width for the column. Good for horizontal scroll. (_default:_ `undefined`) +- **permission** is the permission context which will be used to decide if a column for this entity prop should be displayed to the user or not. (_default:_ `undefined`) +- **visible** is a predicate that will be used to decide if this entity prop should be displayed on the table or not. (_default:_ `() => true`) + +> Important Note: Do not use record in visibility predicates. First of all, the table header checks it too and the record will be `undefined`. Second, if some cells are displayed and others are not, the table will be broken. Use the `valueResolver` and render an empty cell when you need to hide a specific cell. + +You may find a full example below. + +### EntityProp\ + +`EntityProp` is the class that defines your entity props. It takes an `EntityPropOptions` and sets the default values to the properties, creating an entity prop that can be passed to an entity contributor. + +```js +const options: EntityPropOptions = { + type: ePropType.String, + name: 'email', + displayName: 'AbpIdentity::EmailAddress', + valueResolver: data => { + const { email, emailConfirmed } = data.record; + + return of( + (email || '') + (emailConfirmed ? `` : ''), + ); + }, + sortable: true, + columnWidth: 250, + permission: 'AbpIdentity.Users.ReadSensitiveData', // hypothetical + visible: data => { + const store = data.getInjected(Store); + const selectSensitiveDataVisibility = ConfigState.getSetting( + 'Abp.Identity.IsSensitiveDataVisible' // hypothetical + ); + + return store.selectSnapshot(selectSensitiveDataVisibility).toLowerCase() === 'true'; + } +}; + +const prop = new EntityProp(options); +``` + +It also has two static methods to create its instances: + +- **EntityProp.create\\(options: EntityPropOptions\\)** is used to create an instance of `EntityProp`. + ```js + const prop = EntityProp.create(options); + ``` +- **EntityProp.createMany\\(options: EntityPropOptions\\[\]\)** is used to create multiple instances of `EntityProp` with given array of `EntityPropOptions`. + ```js + const props = EntityProp.createMany(optionsArray); + ``` + +### EntityPropList\ + +`EntityPropList` is the list of props passed to every prop contributor callback as the first parameter named `propList`. It is a **doubly linked list**. You may find [all available methods here](../Common/Utils/Linked-List.md). + +The items in the list will be displayed according to the linked list order, i.e. from head to tail. If you want to re-order them, all you have to do is something like this: + +```js +export function reorderUserContributors( + propList: EntityPropList, +) { + // drop email node + const emailPropNode = propList.dropByValue( + 'AbpIdentity::EmailAddress', + (prop, text) => prop.text === text, + ); + + // add it back after phoneNumber + propList.addAfter( + emailPropNode.value, + 'phoneNumber', + (value, name) => value.name === name, + ); +} +``` + +### EntityPropContributorCallback\ + +`EntityPropContributorCallback` is the type that you can pass as entity prop contributor callbacks to static `forLazy` methods of the modules. + +```js +export function isLockedOutPropContributor( + propList: EntityPropList, +) { + // add isLockedOutProp as 2nd column + propList.add(isLockedOutProp).byIndex(1); +} + +export const identityEntityPropContributors = { + [eIdentityComponents.Users]: [isLockedOutPropContributor], +}; +``` + +## See Also + +- [Customizing Application Modules Guide](../../Customizing-Application-Modules-Guide.md) diff --git a/docs/en/UI/Angular/Dynamic-Form-Extensions.md b/docs/en/UI/Angular/Dynamic-Form-Extensions.md new file mode 100644 index 0000000000..880250a247 --- /dev/null +++ b/docs/en/UI/Angular/Dynamic-Form-Extensions.md @@ -0,0 +1,325 @@ +# Dynamic Form (or Form Prop) Extensions for Angular UI + + +## Introduction + +Form prop extension system allows you to add a new field to the create and/or edit forms for a form or change/remove an already existing one. A "Date of Birth" field was added to the user management page below: + +![Form Prop Extension Example: "Date of Birth" Field](images/user-prop-extension-date-of-birth-field-ng.png) + +You can validate the field, perform visibility checks, and do more. You will also have access to the current entity when creating a contibutor for an edit form. + +## How to Set Up + +In this example, we will add a "Date of Birth" field in the user management page of the [Identity Module](../../Modules/Identity.md) and validate it. + +### Step 1. Create Form Prop Contributors + +The following code prepares two constants named `identityCreateFormPropContributors` and `identityEditFormPropContributors`, ready to be imported and used in your root module: + +```js +// form-prop-contributors.ts + +import { Validators } from '@angular/forms'; +import { ePropType, FormProp, FormPropList } from '@abp/ng.theme.shared/extensions'; +import { IdentityCreateFormPropContributors, IdentityEditFormPropContributors, IdentityUserDto } from '@volo/abp.ng.identity'; + +const birthdayProp = new FormProp({ + type: ePropType.Date, + name: 'birthday', + displayName: 'Date of Birth', + validators: () => [Validators.required], +}); + +export function birthdayPropContributor(propList: FormPropList) { + propList.addByIndex(birthdayProp, 4); +} + +export const identityCreateFormPropContributors: IdentityCreateFormPropContributors = { + 'Identity.UsersComponent': [birthdayPropContributor], +}; + +export const identityEditFormPropContributors: IdentityEditFormPropContributors = { + 'Identity.UsersComponent': [birthdayPropContributor], +}; + +``` + + +The list of props, conveniently named as `propList`, is a **doubly linked list**. That is why we have used the `addByIndex` method, which adds the given value to the specified index of the list. You may find [all available methods here](../Common/Utils/Linked-List.md). + +> **Important Note 1:** AoT compilation does not support function calls in decorator metadata. This is why we have defined `birthdayPropContributor` as an exported function declaration here. Please do not forget exporting your contributor callbacks and forget about lambda functions (a.k.a. arrow functions). Please refer to [AoT metadata errors](https://angular.io/guide/aot-metadata-errors#function-calls-not-supported) for details. + +> **Important Note 2:** Please use one of the following if Ivy is not enabled in your project. Otherwise, you will get an "Expression form not supported." error. + +```js +export const identityCreateFormPropContributors: IdentityCreateFormPropContributors = { + 'Identity.UsersComponent': [ birthdayPropContributor ], +}; + +/* OR */ + +const identityCreateContributors: IdentityCreateFormPropContributors = {}; +identityCreateContributors[eIdentityComponents.Users] = [ birthdayPropContributor ]; +export const identityCreateFormPropContributors = identityCreateContributors; +``` + +### Step 2. Import and Use Form Prop Contributors + +Import `identityCreateFormPropContributors` and `identityEditFormPropContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below: + +```js +import { + identityCreateFormPropContributors, + identityEditFormPropContributors, +} from './form-prop-contributors'; + +const routes: Routes = [ + { + path: '', + component: DynamicLayoutComponent, + children: [ + { + path: 'identity', + loadChildren: () => + import('@volo/abp.ng.identity').then(m => + m.IdentityModule.forLazy({ + createFormPropContributors: identityCreateFormPropContributors, + editFormPropContributors: identityEditFormPropContributors, + }), + ), + }, + // other child routes + ], + // other routes + } +]; +``` + +That is it, `birthdayProp` form prop will be added, and you will see the datepicker for the "Date of Birth" field right before the "Email address" in the forms of the users page in the `IdentityModule`. + +## Object Extensions + +Extra properties defined on an existing entity will be included in the create and edit forms and validated based on their configuration. The form values will also be mapped to and from `extraProperties` automatically. They are available when defining custom contributors, so you can drop, modify, or reorder them. The `isExtra` identifier will be set to `true` for these properties and will define this automatic behavior. + +## API + +### PropData\ + +`PropData` is the shape of the parameter passed to all callbacks or predicates in a `FormProp`. + +It has the following properties: + +- **getInjected** is the equivalent of [Injector.get](https://angular.io/api/core/Injector#get). You can use it to reach injected dependencies of `ExtensibleFormPropComponent`, including, but not limited to, its parent components. + + ```js + { + type: ePropType.Enum, + name: 'myField', + options: data => { + const restService = data.getInjected(RestService); + const usersComponent = data.getInjected(UsersComponent); + + // Use restService and usersComponent public props and methods here + } + }, + ``` + +- **record** is the row data, i.e. current value of the selected item to edit. This property is _available only on edit forms_. + + ```js + { + type: ePropType.String, + name: 'myProp', + readonly: data => data.record.someOtherProp, + } + ``` + +### PropCallback\ + +`PropCallback` is the type of the callback function that can be passed to a `FormProp` as `prop` parameter. A prop callback gets a single parameter, the `PropData`. The return type may be anything, including `void`. Here is a simplified representation: + +```js +type PropCallback = (data?: PropData) => R; +``` + +### PropPredicate\ + +`PropPredicate` is the type of the predicate function that can be passed to a `FormProp` as `visible` parameter. A prop predicate gets a single parameter, the `PropData`. The return type must be `boolean`. Here is a simplified representation: + +```js +type PropPredicate = (data?: PropData) => boolean; +``` + +### FormPropOptions\ + +`FormPropOptions` is the type that defines required and optional properties you have to pass in order to create a form prop. + +Its type definition is as follows: + +```js +type FormPropOptions = { + type: ePropType; + name: string; + displayName?: string; + id?: string; + permission?: string; + visible?: PropPredicate; + readonly?: PropPredicate; + disabled?: PropPredicate; + validators?: PropCallback; + asyncValidators?: PropCallback; + defaultValue?: boolean | number | string | Date; + options?: PropCallback[]>>; + autocomplete?: string; + isExtra? boolean; +}; +``` + +As you see, passing `type` and `name` is enough to create a form prop. Here is what each property is good for: + +- **type** is the type of the prop value. It defines which input is rendered for the prop in the form. (_required_) +- **name** is the property name (or key) which will be used to read the value of the prop. (_required_) +- **displayName** is the name of the property which will be localized and shown as column header. (_default:_ `options.name`) +- **id** will be set as the `for` attribute of the label and the `id` attribute of the input for the field. (_default:_ `options.name`) +- **permission** is the permission context which will be used to decide if a column for this form prop should be displayed to the user or not. (_default:_ `undefined`) +- **visible** is a predicate that will be used to decide if this prop should be displayed on the form or not. (_default:_ `() => true`) +- **readonly** is a predicate that will be used to decide if this prop should be readonly or not. (_default:_ `() => false`) +- **disabled** is a predicate that will be used to decide if this prop should be disabled or not. (_default:_ `() => false`) +- **validators** is a callback that returns validators for the prop. (_default:_ `() => []`) +- **asyncValidators** is a callback that returns async validators for the prop. (_default:_ `() => []`) +- **defaultValue** is the initial value the field will have. (_default:_ `null`) +- **options** is a callback that is called when a dropdown is needed. It must return an observable. (_default:_ `undefined`) +- **autocomplete** will be set as the `autocomplete` attribute of the input for the field. Please check [possible values](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#Values). (_default:_ `'off'`) +- **isExtra** indicates this prop is an object extension. When `true`, the value of the field will be mapped from and to `extraProperties` of the entity. (_default:_ `undefined`) + +> Important Note: Do not use `record` property of `PropData` in create form predicates and callbacks, because it will be `undefined`. You can use it on edit form contributors though. + +You may find a full example below. + +### FormProp\ + +`FormProp` is the class that defines your form props. It takes a `FormPropOptions` and sets the default values to the properties, creating a form prop that can be passed to a form contributor. + +```js +const options: FormPropOptions = { + type: ePropType.Enum, + name: 'myProp', + displayName: 'Default::MyPropName', + id: 'my-prop', + permission: 'AbpIdentity.Users.ReadSensitiveData', // hypothetical + visible: data => { + const store = data.getInjected(Store); + const selectSensitiveDataVisibility = ConfigState.getSetting( + 'Abp.Identity.IsSensitiveDataVisible' // hypothetical + ); + + return store.selectSnapshot(selectSensitiveDataVisibility).toLowerCase() === 'true'; + }, + readonly: data => data.record.someProp, + disabled: data => data.record.someOtherProp, + validators: () => [Validators.required], + asyncValidators: data => { + const http = data.getInjected(HttpClient); + + function validate(control: AbstractControl): Observable { + if (control.pristine) return of(null); + + return http + .get('https://api.my-brand.io/hypothetical/endpoint/' + control.value) + .pipe(map(response => (response.valid ? null : { invalid: true }))); + } + + return [validate]; + }, + defaultValue: 0, + options: data => { + const service = data.getInjected(MyIdentityService); + + return service.getMyPropOptions() + .pipe( + map(({items}) => items.map( + item => ({key: item.name, value: item.id }) + )), + ); + }, + autocomplete: 'off', + isExtra: true, +}; + +const prop = new FormProp(options); +``` + +It also has two static methods to create its instances: + +- **FormProp.create\\(options: FormPropOptions\\)** is used to create an instance of `FormProp`. + ```js + const prop = FormProp.create(options); + ``` +- **FormProp.createMany\\(options: FormPropOptions\\[\]\)** is used to create multiple instances of `FormProp` with given array of `FormPropOptions`. + ```js + const props = FormProp.createMany(optionsArray); + ``` + +### FormPropList\ + +`FormPropList` is the list of props passed to every prop contributor callback as the first parameter named `propList`. It is a **doubly linked list**. You may find [all available methods here](../Common/Utils/Linked-List.md). + +The items in the list will be displayed according to the linked list order, i.e. from head to tail. If you want to re-order them, all you have to do is something like this: + +```js +export function reorderUserContributors( + propList: FormPropList, +) { + // drop email node + const emailPropNode = propList.dropByValue( + 'AbpIdentity::EmailAddress', + (prop, displayName) => prop.displayName === displayName, + ); + + // add it back after phoneNumber + propList.addAfter( + emailPropNode.value, + 'phoneNumber', + (value, name) => value.name === name, + ); +} +``` + +### CreateFormPropContributorCallback\ + +`CreateFormPropContributorCallback` is the type that you can pass as **create form** prop contributor callbacks to static `forLazy` methods of the modules. + +```js +export function myPropCreateContributor( + propList: FormPropList, +) { + // add myProp as 2nd field from the start + propList.add(myProp).byIndex(1); +} + +export const identityCreateFormPropContributors = { + [eIdentityComponents.Users]: [myPropCreateContributor], +}; +``` + +### EditFormPropContributorCallback\ + +`EditFormPropContributorCallback` is the type that you can pass as **edit form** prop contributor callbacks to static `forLazy` methods of the modules. + +```js +export function myPropEditContributor( + propList: FormPropList, +) { + // add myProp as 2nd field from the end + propList.add(myProp).byIndex(-1); +} + +export const identityEditFormPropContributors = { + [eIdentityComponents.Users]: [myPropEditContributor], +}; +``` + +## See Also + +- [Customizing Application Modules Guide](../../Customizing-Application-Modules-Guide.md) diff --git a/docs/en/UI/Angular/Entity-Action-Extensions.md b/docs/en/UI/Angular/Entity-Action-Extensions.md new file mode 100644 index 0000000000..d46bd8e194 --- /dev/null +++ b/docs/en/UI/Angular/Entity-Action-Extensions.md @@ -0,0 +1,442 @@ +# Entity Action Extensions for Angular UI + +## Introduction + +Entity action extension system allows you to add a new action to the action menu for an entity. A "Click Me" action was added to the user management page below: + +![Entity Action Extension Example: "Click Me!" Action](images/user-action-extension-click-me-ng.png) + +You can take any action (open a modal, make an HTTP API call, redirect to another page... etc) by writing your custom code. You can access to the current entity in your code. + +## How to Set Up + +In this example, we will add a "Click Me!" action and alert the current row's `userName` in the user management page of the [Identity Module](../../Modules/Identity.md). + +### Step 1. Create Entity Action Contributors + +The following code prepares a constant named `identityEntityActionContributors`, ready to be imported and used in your root module: + +```js +// entity-action-contributors.ts + +import { EntityAction, EntityActionList } from '@abp/ng.theme.shared/extensions'; +import { IdentityEntityActionContributors, IdentityUserDto } from '@volo/abp.ng.identity'; + +const alertUserName = new EntityAction({ + text: 'Click Me!', + action: data => { + // Replace alert with your custom code + alert(data.record.userName); + }, + // See EntityActionOptions in API section for all options +}); + +export function alertUserNameContributor( + actionList: EntityActionList, +) { + actionList.addTail(alertUserName); +} + +export const identityEntityActionContributors: IdentityEntityActionContributors = { + // enum indicates the page to add contributors to + [eIdentityComponents.Users]: [ + alertUserNameContributor, + // You can add more contributors here + ], +}; +``` + +The list of actions, conveniently named as `actionList`, is a **doubly linked list**. That is why we have used the `addTail` method, which adds the given value to the end of the list. You may find [all available methods here](../Common/Utils/Linked-List.md). + +> **Important Note 1:** AoT compilation does not support function calls in decorator metadata. This is why we have defined `alertUserNameContributor` as an exported function declaration here. Please do not forget exporting your contributor callbacks and forget about lambda functions (a.k.a. arrow functions). Please refer to [AoT metadata errors](https://angular.io/guide/aot-metadata-errors#function-calls-not-supported) for details. + +> **Important Note 2:** Please use one of the following if Ivy is not enabled in your project. Otherwise, you will get an "Expression form not supported." error. + +```js +export const identityEntityActionContributors: IdentityEntityActionContributors = { + 'Identity.UsersComponent': [ alertUserNameContributor ], +}; + +/* OR */ + +const identityContributors: IdentityEntityActionContributors = {}; +identityContributors[eIdentityComponents.Users] = [ alertUserNameContributor ]; +export const identityEntityActionContributors = identityContributors; +``` + +### Step 2. Import and Use Entity Action Contributors + +Import `identityEntityActionContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below: + +```js +import { identityEntityActionContributors } from './entity-action-contributors'; + +const routes: Routes = [ + { + path: '', + component: DynamicLayoutComponent, + children: [ + { + path: 'identity', + loadChildren: () => + import('@volo/abp.ng.identity').then(m => + m.IdentityModule.forLazy({ + entityActionContributors: identityEntityActionContributors, + }), + ), + }, + // other child routes + ], + // other routes + } +]; +``` + +That is it, `alertUserName` entity action will be added as the last action on the grid dropdown in the users page (`UsersComponent`) of the `IdentityModule`. + +## How to Place a Custom Modal and Trigger It by Entity Actions + +Incase you need to place a custom modal that will be triggered by an entity action, there are two ways to do it: A quick one and an elaborate one. + +### The Quick Solution + +1. Place your custom modal inside `AppComponent` template. + ```html + + +

+
+ + + + + + + + + + +
+ ``` + +2. Add the following inside your `AppComponent` class: + ```js + isModalOpen: boolean; + + openModal(/* may take parameters */) { + /* and set things before showing the modal */ + this.isModalOpen = true; + } + ``` + +3. Add an entity action similar to this: + ```js + const customModalAction = new EntityAction({ + text: 'Custom Modal Action', + action: data => { + const component = data.getInjected(AppComponent); + component.openModal(/* you may pass parameters */); + }, + }); + ``` + +That should work. However, there is a longer but lazy-loading solution, and we are going to use NGXS for it. + +### The Elaborate Solution + +Consider the modal will be displayed in the Identity module. How can we lazy-load it too? + +1. Create a folder called `identity-extended` inside your app folder. +2. Create a file called `identity-popups.store.ts` in it. +3. Insert the following code in the new file: + ```js + import { Action, Selector, State, StateContext } from '@ngxs/store'; + + export class ToggleIdentityPopup { + static readonly type = '[IdentityPopups] Toggle'; + constructor(public readonly payload: boolean) {} + } + + @State({ + name: 'IdentityPopups', + defaults: { + isVisible: false, + }, + }) + export class IdentityPopupsState { + @Selector() + static isVisible(state: IdentityPopupsStateModel) { + return state.isVisible; + } + + @Action(ToggleIdentityPopup) + toggleModal( + context: StateContext, + { payload }: ToggleIdentityPopup, + ) { + context.patchState({ isVisible: payload }); + } + } + + interface IdentityPopupsStateModel { + isVisible: boolean; + } + ``` + +4. Create a file called `identity-extended.module.ts` in the same folder. +5. Insert the following code in the new file: + ```js + import { CoreModule } from '@abp/ng.core'; + import { ThemeSharedModule } from '@abp/ng.theme.shared'; + import { Component, NgModule } from '@angular/core'; + import { RouterModule } from '@angular/router'; + import { NgxsModule, Select, Store } from '@ngxs/store'; + import { Observable } from 'rxjs'; + import { IdentityPopupsState, ToggleIdentityPopup } from './identity-popups.store'; + + @Component({ + template: ` + + + `, + }) + export class IdentityOutletComponent {} + + @Component({ + template: ` + + +

+
+ + + + + + + + + + +
+ `, + }) + export class IdentityPopupsComponent { + @Select(IdentityPopupsState.isVisible) + isVisible$: Observable; + + constructor(private store: Store) {} + + onDisappear() { + this.store.dispatch(new ToggleIdentityPopup(false)); + } + } + + @NgModule({ + declarations: [IdentityPopupsComponent, IdentityOutletComponent], + imports: [ + CoreModule, + ThemeSharedModule, + NgxsModule.forFeature([IdentityPopupsState]), + RouterModule.forChild([ + { + path: '', + component: IdentityOutletComponent, + children: [ + { + path: '', + outlet: 'popup', + component: IdentityPopupsComponent, + }, + { + path: '', + loadChildren: () => import('@volo/abp.ng.identity').then(m => m.IdentityModule), + }, + ], + }, + ]), + ], + }) + export class IdentityExtendedModule {} + ``` + +6. Change the `identity` path in your `AppRoutingModule` to this: + ```js + { + path: 'identity', + loadChildren: () => + import('./identity-extended/identity-extended.module').then(m => m.IdentityExtendedModule), + }, + ``` + +7. Add an entity action similar to this: + ```js + const customModalAction = new EntityAction({ + text: 'Custom Modal Action', + action: data => { + const store = data.getInjected(Store); + store.dispatch(new ToggleIdentityPopup(true)); + }, + }); + ``` + +It should now be working well with lazy-loading. The files are compact in the description to make it quicker to explain. You may split the files as you wish. + +## API + +### ActionData\ + +`ActionData` is the shape of the parameter passed to all callbacks or predicates in an `EntityAction`. + +It has the following properties: + +- **record** is the row data, i.e. current value rendered in the table. + + ```js + { + text: 'Click Me!', + action: data => { + alert(data.record.userName); + }, + } + ``` + +- **index** is the table index where the record is at. + +- **getInjected** is the equivalent of [Injector.get](https://angular.io/api/core/Injector#get). You can use it to reach injected dependencies of `GridActionsComponent`, including, but not limited to, its parent component. + + ```js + { + text: 'Click Me!', + action: data => { + const restService = data.getInjected(RestService); + + // Use restService public props and methods here + }, + visible: data => { + const usersComponent = data.getInjected(UsersComponent); + + // Use usersComponent public props and methods here + }, + } + ``` + +### ActionCallback\ + +`ActionCallback` is the type of the callback function that can be passed to an `EntityAction` as `action` parameter. An action callback gets a single parameter, the `ActionData`. The return type may be anything, including `void`. Here is a simplified representation: + +```js +type ActionCallback = (data?: ActionData) => R; +``` + +### ActionPredicate\ + +`ActionPredicate` is the type of the predicate function that can be passed to an `EntityAction` as `visible` parameter. An action predicate gets a single parameter, the `ActionData`. The return type must be `boolean`. Here is a simplified representation: + +```js +type ActionPredicate = (data?: ActionData) => boolean; +``` + +### EntityActionOptions\ + +`EntityActionOptions` is the type that defines required and optional properties you have to pass in order to create an entity action. + +Its type definition is as follows: + +```js +type EntityActionOptions = { + action: ActionCallback, + text: string, + icon?: string, + permission?: string, + visible?: ActionPredicate, +}; +``` + +As you see, passing `action` and `text` is enough to create an entity action. Here is what each property is good for: + +- **action** is a callback that is called when the grid action is clicked. (_required_) +- **text** is the button text which will be localized. (_required_) +- **icon** is the classes that define an icon to be placed before the text. (_default:_ `''`) +- **permission** is the permission context which will be used to decide if this type of grid action should be displayed to the user or not. (_default:_ `undefined`) +- **visible** is a predicate that will be used to decide if the current record should have this grid action or not. (_default:_ `() => true`) + +You may find a full example below. + +### EntityAction\ + +`EntityAction` is the class that defines your entity actions. It takes an `EntityActionOptions` and sets the default values to the properties, creating an entity action that can be passed to an entity contributor. + +```js +const options: EntityActionOptions = { + action: data => { + const component = data.getInjected(UsersComponent); + component.unlock(data.record.id); + }, + text: 'AbpIdentity::Unlock', + icon: 'fa fa-unlock', + permission: 'AbpIdentity.Users.Update', + visible: data => data.record.isLockedOut, +}; + +const action = new EntityAction(options); +``` + +It also has two static methods to create its instances: + +- **EntityAction.create\\(options: EntityActionOptions\\)** is used to create an instance of `EntityAction`. + ```js + const action = EntityAction.create(options); + ``` +- **EntityAction.createMany\\(options: EntityActionOptions\\[\]\)** is used to create multiple instances of `EntityAction` with given array of `EntityActionOptions`. + ```js + const actions = EntityAction.createMany(optionsArray); + ``` + +### EntityActionList\ + +`EntityActionList` is the list of actions passed to every action contributor callback as the first parameter named `actionList`. It is a **doubly linked list**. You may find [all available methods here](../Common/Utils/Linked-List.md). + +The items in the list will be displayed according to the linked list order, i.e. from head to tail. If you want to re-order them, all you have to do is something like this: + +```js +export function reorderUserContributors( + actionList: EntityActionList, +) { + // drop "Unlock" button + const unlockActionNode = actionList.dropByValue( + 'AbpIdentity::Unlock', + (action, text) => action.text === text, + ); + + // add it back to the head of the list + actionList.addHead(unlockActionNode.value); +} +``` + +### EntityActionContributorCallback\ + +`EntityActionContributorCallback` is the type that you can pass as entity action contributor callbacks to static `forLazy` methods of the modules. + +```js +// lockUserContributor should have EntityActionContributorCallback type + +export function lockUserContributor( + actionList: EntityActionList, +) { + // add lockUser as 3rd action + actionList.add(lockUser).byIndex(2); +} + +export const identityEntityActionContributors = { + [eIdentityComponents.Users]: [lockUserContributor], +}; +``` + +## See Also + +- [Customizing Application Modules Guide](../../Customizing-Application-Modules-Guide.md) diff --git a/docs/en/UI/Angular/images/user-action-extension-click-me-ng.png b/docs/en/UI/Angular/images/user-action-extension-click-me-ng.png new file mode 100644 index 0000000000000000000000000000000000000000..675f05217acf03531f66ad82536cd26d0e693f89 GIT binary patch literal 142395 zcmeFZcQ{<{+App|2tkUFM3h7ly(FUd2qHSsYt-mOuR}zLo~Y49^xnG>HPNFCW(;AX z4#sH1Fr4MP_kQ1f_V4WXH#vWvYje3~nYEsJ_s?_R>w~(g0wwuvasmPZO2y~TGzkdE zD+vfL2$Nj|zEP^B@+Tm;tZpkStF9<3%dGy!+1l2@ih$txhs0!3BQ0IJ4ix?8`=!zs zEZ?;~yLy4>JJ~C_D{<`MFP;-!V(ERyyqKTBq1O=p*5GGx_!kcXO;$VC8$FH;J;5*X zXi0fqwxenN1CtV`Ir)sVJ*hd}JiL zyh=>IP3qn*eHYQ)BS*{@f&mX8?FlsCye&okxSBI?M6mkTD+EE^GQ%_+7mngE#6ihq zmODfQ;SPlj85+!5uA-JKBA2gJEBDOY=FxV|e_t{o_yKM7U5t=<{LtS=kf3=;eT0L? zQdX*2h`B{6^cp*XujTh(qDQ7=BG-1pPflz(-g|bi?@~z3fObEN{EitDw9DfZ=?iO#Tak#|`8=MJs-6`o9rtKT+0Q%U!hrve$JKV)pZ@{E{=jD#!u9rtx*ViD=F zx$y~NkgabgA=7sm!7GG9W!5gwBAOM*D=uZqz=`V`V>vUQzR4DTJhAX3j1r(0)Sj2}xKsE6VwVsSsP7w+)Xitk z_UO}1RrlVZZRuI2*!NRr)8a0ITVgjiZTvb}o{}y|E^y?;ySNp9eRitNg^*$0V=5mK z-W`Z?C0!k-p#Daj?X`N#X3@HXl8Ja_;g^hyHE-dP9YSYm7%SvMWwk9gROd)VekdW>6)TLgveEU8lyO8MC1Aij}6NMbGFl`CR=d@idsJk4Z5 z#M}B`+7Cifp~>rNwC`CCI5oO^IV zHeKsQ9NF8rE25p!%2zqN8C~VXuLxcXe|PuibMa3RmdrEZG#dA6K03#dTar{$&Agkq zD|MIjBjWq5uf$CsW@Vc{(tY=%k+m(nY8Nb;ovSX`FOxg^%>8j{w5menPfhnr2BDBI zVn5~ggng;nB0RsS{gk|HCVKOFP46t9U~i9k)e|m?cni0xH>KA~dTv+J9;%u4idHdh zFsOFl5~lD9u@}Ck)=6^c?$6VH(=^Pvj~*R=Xm!Fk7YVvIdTIHB?pvl{g_P&t9}Y4n zT;;fAc!`v(;Me$soVUvTYoDJfe4+Ngt@S~qTfe)fd%qjrZP87&NNmpZ;o0K{O`nLK zSKXH^3VJDTpafMEebM}E{a)JxWL(*I#@{Y)ZtK6`xvTrhD=s#U_ajsMF*}yVFM{bo z(!H;PU%B!ea%$Ci)SKCGFNup;1cFkZ59RP=>uAsy78EuV@p`zsJGlFMJY0S5zKndi zw((P>%uQ{DVJL3-DPnBQ_677BR1o?IssdFK&DfHr&M){$v8uG{v3Gs1Wv`+6GW=t+ zxN**wINS~{4_9g)*<aX?e8fUiOEf8Pqt+aBvMbs-4#T}&;#l!ODWA4=v zw!Xs7*U1_!8WmMJ=$i;j#65%^qN_JUIclxr_oLkurO$q!r&3U1`j-)xuTvU6DSb7a z_sUuMecFYzaOHj#&om9>i#!gU6-@eO2ZjaK;1iKtUX4q>o7v#HeVHEF^ zsprK`gxn@(d&KAbla8!+cb5ZblW4EfK8~!TW##ha`keGFNhGO+D^}0b@KGsI*?pao z(ij8Wx5w75dOoEb5JjDex+agWbz{Eq9xWc==v$`k`oq&Z-W|)A_!e z<=*#CA5~bgqO0i>1?`Rs>ou}w+h%uX8ye?tI|}>Gu73K-oonjd=uIYGEK%+~CebCa z;v?uM$%GJ1BTZK9~&2_q~oTllWfLj#j*{AKAUH{vH6 z(OYo`B-Se_e|wyU!rZ5d(*o5k(yJ1C>_g=GboSl)rPxJ-BMW_vkE{6^45;tYI|*)^|Gp);{GUVP-k;7rQyLm@#g!!2o(7js+w zZvy2{Wr}j1==#1%U8?LNBTdF%q|FRtR$-TJ11hu zi784b=7*nWR#kk@es16%m_INm$InC;Mt3Gmk@X;DQWWNU@OB2X?6T~T8aX(W4ig>m zG+ApcKf1cxz?;qU-FVyngWr#cPrCD8{l_)!G(^FB-x{vYLz35$ehid@R?gtPp@&a@ zbRNiMMnZV7FL}763>Qo^^wF=X%+NC^1(4}JuH#ebgH5HjWG6j&qld<8^> zCtLM-jX<`t+wb2;)6#Pawx7xDbVaLNO}lN+V8Dy zO>;L~IXK*8Mf$I=d#0fD3}PXi$QG}BRBI!ryRKV^VOKtU5Prk2gK;TSDzN`>4LVoY zR(3pneER@~su1ZAR-X%hGVHM7cumMdut3o3&K{VZw(HdU>4g~nu32?wl3&3_KD znXyS5_Q|prM|qrfRG5GnUt^q{TYtIb9DPCcB*j!QDDaRNiw279?eOY)>kb=7H$h#w z*PzkJwJ9-YGH3Co&tAJn&Y|G_`BYGvOUp^jX-0p`vX?!`>omZtz-wi}F9$O`uhs}c z2LJjt9u^VC)ck_!CzG~hy{{3b8}TD&YkMmaq>Rl)7H!yq)Mm0Sf*|5C=v&DBhKl2BMn|uXSh%cSQ*;~FqWB_`R($D%6_QRexkxEZ z+*(wRoV6g>2p)PRIs2un#jYgt=4ExYk(~S+a!CbYy>yhB-ek_C7flQZr0ocQ<@%dt zgK!-kecXK0X#{uD%0*0z-;s@6l)6x|TCAwafB52*By1A|=@O>l1wxD@D?LSP6%_&w z;F^qpgzy>xF>pl){1On}CLsCint1=Mr3=aeiaN`$$AYgqQCz@8ieZz!ThVK2Gkh zyt$p+SpL?@Kl*uQ7l~U-0kE{`J=Xv8n!lH+{q>%=gbt|LN90H9cR1 zsM;G_V5YCmcTw_@IPd@GyMKLN)5^`+!Q=dKZ6{lI$;W?h@-JWiy_GocIbr^ZP=Dis zzrF?7K$2XX_rF+5lHA%%B%6Rhnn3ZH%u8>=4LGU4iB%ivHfXGN?JZF#6&rm&m(s1b zAvq>jpAiy%e2|?@^ySTsXGxbySid;jP`^48!6lbaQr%$nog-J>Ks0D8-}cRj+hSU~ z;@nsLp_9y!0G|<`VSez+*Ztiluq1n$01^(ZuC9KbWhMRvx zDyOS#s6h=96EQ6<(?20`J9`|dUSvo?&q`iWYw2+wl#S(2sLQN=MQ@p^l&FM+WBw0@ zB_ztYtNyryqZWFr7W)UJA-lr%K%L3#h5>g^Zqy&`Z4JpfacKs;>hzC@NtST!wQkU) zQ&}Ec;-9b(S*<)XMJ1#@-=qXd)=;1NLhcWUDGjE1T}f>3wlKcjf1H;hcl}Q`$o+Y? zOi*1TYtE!O<;tH?;;Y_!x7Pk_;WV)tF(%W%1dqSo-c9~77LvuGng-hB zmNYaT@o{i+T5SLNHiP+f^GV@jUQ|3Y?W8rZ6@u}$e=tmzG}aMCK|2`Rf;Xybhr~lnULkFaqkeFzdwR2O@LGLnC`_s#}9zWsboWQ`(E?m$%p672c z$D6lC?Sg4kGbE1TDFXKLA)|KoV$U~`MCAfLQf|wG!(F8;3NcYPbd40_>gwVGN=;^J zZO84kibWi!(yk4MqH2fTjfEpd=;t{n*!_jd4cRa%_|tEXG1zB!xwqCE&;N*B&HvkTwGF$y7c5y5Zq3MIagWbrFfph3>S&HW zpNHN{9UXZ&Ik}MeE2guiBqVyyO3ygH@-PdQF%CxGHNBd&+`FwW8@t&3eyF)^V53E^HbSD0foa6fqMeXeEcL*F) zBXgZ8$SMyuSL{9T(}rB6!G@^7$8+HMCf7k*-9BP9WxHLnA{Dzd?DGH-GWP~)s7jrH zSVca8U9p%5%wvDeCUZ!(cye-bU#x<*f`vqXyp4o{w!3EJl-0y%DN!$_&R8d001g6X zSnWzn>$TDvdkL6P6{(#Fo-;BHrZf3W+n4Fz0Kt-K^eU8)Cq1tdU6=fbZ34WlI zWZ6=vYGPgaWIwAjZ@fS)b|n)eNu8e`w_Y9d(q^GE6n#R$Yk7C3sO&atoev^<%HqeT zbt?~4An%RB)x2FnM?5u%dy%xhzW!xKalU$}!{#A;Bql<(-Pfm8!bT=+*=60;ub16) zhVwLFapnbH7_Y)ZPW5VM0lNeWdGo?(0o1OKOGGidk!GBcW7` z;`b?nlN#*Pmu6n)s?-m+%pb`zg)8wkF-w`o;jl-tQeH1{l@`5GF~(j;>NpQS)fkDb zca6vj&_J5x?gR_&@s+fvCFA)jj+0v@mpDK|H8zhxrzbiM?16$sxXx1CTaw*f7i+nm zYL=+FIsr7qP^;z&a{GA;GbYpmQreIVdu%oYssAd{`gr|pQCPJRT zYj9ITn=aiCkx&0ckRnV)c*XE2Tny}->(2^NU~QjWzg5cbWa|T2M zqYW8S#qKR=bNWT^)oZJgW3HF22hH?|(wY%Yqx!=DB==O`dwQo)^Ng+5CYPUIunVM? z54+w|4tSE6!8YrK-tDfl&WEU3j|2+AeCqNi`IWzYZ_q18}KYW3g3=jmDUv1pqV$HQff0{n~#MF)G3*?;3IMh=< zLJVo7;jnw$!(tDzx=HKlnULj8b|tK}2aVc@&u)RYD@-xRtwYli2gTIg`ERER1|vr9 z_$l7OG{MbB;Pnn3;D9D`tj8|+XnzSk1wNG!ybXTk{|hI!zqI7}1FFg94k^8*A5>RA ziMT;j>S#OOxZCWiMdqo9FdQx#`6`o$%a~>zX|OygND(>#!&=k`Aw}RSrJ0j37PK*=&tN5pxPAzt_a>}71_)XK0F*)T=-D& z>~;$aA;fK1QbG{!j<8;-TTZnX^s8W47fusZ6zjh zA@wxfT>Q7jn7S?W!}mACP_edNbF{HG;1>bNEdK(P@w78+nh)+L(~LwtR>qhBSc!mz zC!WPzb;JX*{J9pGZ+%huqx zlA(&QH(#+z)n4tn3gn;$n+?G8C9CwL0h89znQh8YcfG_fLR%Ff0ynLlUW^x6o|s== zXd5xz2?2!nGxZ5SAR#f{fQvDWwOM&m*iss)(GvKio`bx7I9))9y5bc1laBt03IG=d z)yXIfG#+j%NL}4s8HvsCIyLhbf;H_ot(b&I^5W!XUHeSe4P$Qci%RY+7%!IeG0}I0 z34tk=>7A87%$wkj4-woAJ%gWXb`AhJk7V$i7L37mUagu;y1w|0lqsen!$mU?1!D#A z9~>T@O~j7R{`gVg&${&^P#fD3OpHKz%`*bw#J;x8$mi?2#vUG$%fEkAtSs3M4hh2U z$4IV+d!MPIN-AKpKcYVKBludY|7Zy*Bcr;R-F|J|4`sZD_ zzlXh~4NO^}b>|bz{UNKw#8m1i!SeY`1 z?zuKMz$#dv0;r>&fEQV!j{tM|JByflmUmcq^Yd3Sp5`<>a_nU#A~}wbJ+YFssjX#yTNCE*ojrv0bEQ9E0Rb6rV2Z zS7NoYX8Gsg-f)kpm>aqdXHMU2U!i8KOAfm;Tl!``p)@C&L zh3}&vl5>Y%^{C&3o2V51A-2{V+?2){V_Na8>{}u+;#WZG{N38(Vo_S&a;H&iALGFk zNtX6ECqg@0v0?|2RY%Kd@;>@L%KqzXjlXQ@R+iY=e3xfddU$!kmEWFN52oA-V>-&i z#@Rv%Jw_xXlSqx{eO59WF>|DgfCC$i3PgpucAOpyzJ`5_jO1xAmGs801xVdE-rD^! zZ5Fb>C^f@Vy^?vH>py5;-X!_Zq26{Q4bJP4zE?KBBdK{z-3scvSv3}(@?>qPabt&b z{rI%^LqWF$s6~Q;zFe<3(nP!d_0LW=D#8ZO9ov=h9N92;Z#u|b+4q)WtMw8csmo0+ z3vW%B%os%7U#EL*>6clVTDR?~o^F%Q8(X(!>HwfdfyC9_yZA*&Fp~4gs5LE=N9;Hy zaGu3+tJ*v-(R>t&fXLw~U=Q&^f1}=_@v{~a-)b8P{^%)) zn*wh|o;!E-^MNp|Xy2XVI<}49&0SQm9!yQp-0IKVbyU{&enmGiwKz=}L!i5nA3S=0 zi9te9tTUfw=y-3u{YJ<|%KnN5*nx!WsaiV|(@~b%@2OIZ0hMZlNUd*vMwW4#YP!-mvYyUdyseX!392vrDhs&^60B9ZzZf|j%NuZ1vTwy8aZB9W zWv*wvB({vYf);CJU*_ui%SMu6>g4pj_fn$nF8r02cQqR5gPW>?c8i)xl1o(z_glO% ztv}Ou{c~rT39jw+&o7>+j#STM<%RKe;1Cj1^@jGXqgs$aj;=QM`sBewFc49D6ovBR zw-IE&i6ZmcCN1tm#gac<&x+Y&_we5)7E9z99ypjrSPad<&;hWidB3H}sr3<5%h@;V zu0^a!v!!>P`l~5pNt){q9UvRC>+0xO%ZwEZlIjig_wU5H zuCweELJ3~(jdb>Pk|fJlJ(+K6y?96&8%;|Am*hcm)sKhtiCm^` zL#~vaS<#$jRlV!`a^v|tlt-%EqVo>p(MaSIubnxJ!?-OWq)oEQ?_?_#d5=UHeB8#= zo0p8^@SHgcsY1kv{cahIxm{=AHeSffB;*v0-PL5JcdUISelUIgkdiRm6kCo_b~E~wo7>Xom4Bw;f0hE5^d7mi@v0Wxw}uNIO~KmDeN%Z!=dCSJ9gKSwNnvTu+B5?*kGIPEO96pl$4tm;KYyP(h?k z&LUtXYS|B=-d}FqXgi}DIrCf8^2x?RU|UgHxRX!b82C(d@=QK5j4|*@dD~X+a~y89 zkFI;MClWT%-ok-7Wt}m8)B6BF%P~S;>T!7W(OFM2tgc$}mE!1cdYtH~X&2ccd(otwqeP1$# zL>C;eBSi0B5BEexTeSPXY=j1crPO*JGS^f0q;&*D%~Dfz6h4(krJ_>esWZ_@Wn;;_s2jsYz^>3M2NM z`?eRlZYv``+nilj2wX_HXvNTU^T})V()Qlz!#=64Xk8N@0jjgvyGIobyjyNtvp)OD z&S0D>&Icr^_-YJr@oSHDrwRz{e0+Sq!qvxp9334a)2(LU5nKQm;(ot1^&C_9+EX>V zAwlGLcD)``I;4CFzk|wAo?sC-x^ArzHTD_L*_1>JoQJ$XqtJ0vvUyK5#919O+q1F4 z+5XY{~oXdME|;c=Oe=u43lT)Mxjnz)Ni#?Z*m$ zZaf`(8e0bT_(gcUL3Tqt+)L>t3C%_^)En?R zfpXDdfMr3!(k11i1BB=aY|Q|8^_S0AAE8#-k| zIBE#&ed;$-P3rb)L+n%iOvO|sm!ceuL)Me)fFQ2hwJ)&hw^QAk4bpGrlx^91J`_>b zkWZ)TH`zd7U*T)?Pzf)9Lt6LJo$8U}+ZXh}+n=eEE>{d6uFUTe*c&d_?W>JMu&Um? zGJfjsr+f-`&h`B9sS#^q8Yx`-#8>s?|5^{C_wIH zQCGKzyJ1$xpYx&eG*|mc9&dMfi$B}x5irs$XZvd>o*TqzrZBo#$;b8cTWzjC^1xAk zr>LwRxLoQux-US)6Xv*bafy3>D%+f?^|{RGZ*jka7DoePKsJE$ikSu=pazuVkBa0; zMaX@->gFO9>{s-7dE44}lEv!iD<4>W?HZ*As{J_g;kfvTTUa+a=VfQj)74zH?tP)z z*{`iavXGtjM(*eb3J|&@<&=0G9mF-`{@|I2Q^@U#y1I zVb>A&LiPNP(I>mS-K>&LpvVF5-#MV9%ax}HCQL6~jAZ>xeODNDWEj(lLIoLCkV(3WR03b7m_8ObK8FHI%wChYcCGF(4( zekzH%^BE+X3vP$@0S7oW+pm3SC5^{6u2JMn(r5;F9c*|XZ#E$6bWI~g+*X!lAhl_B z#WkfYlZqbm!$cLa5~t6;#w|hZ%Q8p|bYrfv$ae$aMDi_b6?(UP5dd&KIiy4wvSwUS z6Bnua{RU#_l`&g5F@$NgDVau%`}NKG?555##@*UPqht3Yw(U||3GCw)3h@$6fCD{< z{I=??HjdF4!C!21J_4b-3XBIcjSB|~i*Co86WJzibi8dlI;G&@F|!rgl|Zq6j*Hz1 zQnLvl&G7x=tn`FUqvpmY9$(9&Gu*rsBDP^RX~Z#*)>6XkEI?`4&6D`2aGOr}| zMzq<4nIu5LT4w$hf4&e|PJX5B-Nw|X1-5i>cCERnTl_ZN8#8V@47&Dqc2Mz!2^($N zcPd#VGsoy*F;p*kS6E+hN!e|SzNqNQY7~v7ip*rEa{}+>Ps`2y93}O(4Ung>Of0Uc zi^^$g0#F&WHd!79EzpBn`6UU*r^~YV?MQIu{kXSZLpw|m+v|laR52rgOP{=PL!Zks zcaU21F^G{v;}GoiVM%t#v=_M5VeYqL8&7NM!*-NpR;lT@Z9x`8{KGa)kg@P*F)x$! zRCpSI3!ChHa43Kz>fF|7+-!*?(J^w(dzdo{92|9@9PJ|Zh33M+bGU{^)G6sAVDARA z^Z_ZtjXYJzPYuk}G_9#-FgEpG=xIC)CSBZeDAhIf<7N^Y$~k;a2&vU7$#uRo9bD%u zp;m%lbZ#a>#%0tf{1CU@nSvexue23p==KFJj0*osiCko&247)HhRU z0KHq2wAI;o~AeIuK^GHJ0Yu9k0V+%D@c27BSTO_w1K_AfF3*--c40I~t!xetAt9(XEXiPMhKO z7mGQ0B7x)kDm3?$F&Cf1^!80*7xk~(s|i8{&!7*y(2IF3R9-#qV=Y;dwzHu#$GgKV zsNTvPS&NP7M^(53vF_~!PWPTCQ9pamafHiG!uYwCz6BlGlRDAdJS}|v{R4{~7Caxo zbH@&0bUP);vm28$s-<*UZqMt9mlvrpQ*eftFJE>aNlEfjiT$o|omtZDjz7!P10(EG z4WSyl{G|S(R3e8RdcetPvtM)XSw)9ku6$ofMH?-UqOf*A;6YxU4>tom)-N0swSkM* zvv$(4fU2=)3aCty!%M(AcCHqd6-AE(+J$*LuEWrS6k4KBzUR}IGcwKD#!Fr`;eJ2u zi{wTCn8ipWEtlSvb4RwcwZH$7<@T>dyJ5fZj>?>_#a|)R9|m~AT*W0NEfU?Sp1TZy zJ)w1%yblZT@TS&y96d~X#cb0-1Bc(K)aVMy!K~xJ^DKKOAHG1hah#(GipsEzE^K4B z{Tz>n&DJ*v+=f3bZKWT5>lyMp=(7@0T#(iCN0Z2L^?L9qaxME-W zsN8VbY_$9;TbiJwucN-cPXYih_-?Po508HwrcglpApAl_Ls7jR6ie;+I@)w3|2FTS zh#0`X`+w$|mvzO4KWahUc3b8N2XM>ddm#e*guyFWAfECgoIn+jCgG&70vsavF9#7@ zAfkn~lF*b;k8^&ralDTozX348D1szk*@vaPaVJ8r_O-^u#Dx0~|AB!4^U>`7!`T(8 zSXWPz&1<_`jL(AVTC#%Bc&<=7NSgZk`I+);;ISim1C$vJpi6~iWyU=G%3!p_W^*%I zp1!Y7s$Bs%10f%eXxYc4ai*EM>MQFV7$8 zhzPF2%=z^#r>U)8MGAZx^k!!$G^hdfJ@Pv2( zLd4RYQ&u@mP{1TjT;!ozAorXvvMfcy&y&$kC0^~-B%tXY$(IRoK#bgmHfnSL>-`YO z$?`jaDp%T{A9M81u;CXu{oRi{yTQgPgO>*RhnmmkBmu_Jgz5d!ICneNAK-`K{e3d4 zngEaSED7Gk50UxXWP%7vy#8!4O6QA7fSLW#Vu(uT{$y6?ECg_Zrc(&sOnu%xS*0&2 z-kftzo#yk5Dy1e$`9IkL=8koS{}ARsgu$27vj5+bnCwNk*NOrF(4De#az<{PRjV17 z3mDVIEbhL995$;v>tiC2f0lT=3L^3}+XRiwM&NCK0pW#nr~^>;sDIyNErmUts?_Sp zsnk}dr=^rOOQ?Oyn>fxUbe*Z7kL-v<59(X^#<~f`H0#JM)mP;S7cRd&=!wjs}9B@zs%=H5X z44%H_=m^O>t>Yt#$~#H(sa`L>dx&&kDtSos{HBQ?G2rQ1xEDyp~1;Jmuj`Mw*x7v>$S^|*C{GJv)Vr5N!!r}M4>LGHq`a4*v$=} z^$HtuuGmUjU)E#=u!L5n*T{>YIxi`y8a&-h=^CPp8+@CkfvFjV^f=AzCQNZI;lxug z!)Af0WCD*-ErC6qIei44uCDO|bux6FO>0c8ol*i;e# z*#`QwEAZWN!QfuP4v6ws2}gtR3egLq9O@@d^#XAm-B1nO(v(S%$I;CCXME?zqkiYW ze(0BD*?jE?w3Q9EF(za7naIj2lw+SY^sP<+-P~0D1^rMxLpj(|B7j4r&j#T+Pd&+V zlGyt?E5RpB4UrAjRO@?E!Fe((V;@!^7quu*7KZB$^-gDg9Pk=*pj5(Dhyzc~71hqZ zvTCnVP*!4?7OG=7o(61!TJ|Bl6joNZlwqKS1GvjZGTzORH~>-U!hVnd8=TeM)k{Vp19OnnQte?EJ5x7gFL_Dn0a9|8^Dhb8Z z)aNlfSFe~EOP2fMmoNhWbywNmoxM;gbg9^eH>$cVMI)OYj$RF3 zgzIQY4Um5k^pa|;7=k0epVV&p13=cW&?F0<1ZaMiEwC`QjGT~HQ5nzR8}C-CW7pQv zvsA*6d-z{xBdew1XYj7 zQgtDcN-dv-X79abL8W81c3oj-m5isx^BKGVzIv4Jd;g#84lJmqiTFb0L~eC zUYPc3vYIQ!fXeo;2qH;2d6ZUq zvceuF_0)MK^??~VV|5D>yUy>mOgxzJDHMu*sT?02ih#1?jNDYK$ z2y9M35A}4)UG*{an3ZM((GmmdDfPeOhkwvcVYyDh&!Q*1a{!ao|#@jTl2JE!_flP9W!|{S$mHp>&R?ou@H(E5dP80k;L{p-o1wTzplX7RifHjHbS;kBSOh zHF0W=T@+GuD2fye?rbsgZWw=d8;lA4apR1Orr+NyD@ZD|d1UT8o*TaUG#GjoqfLM2 ztL$D%u|QdOhh%+jDGzn<=FW?$46a{lIjR>Y8SqpvNnz54Ua<~FQm`lisWD86R)10- z&Awvx0LfU3(TNkCS~hw_8r`P3;#g){Ol?(0cg4)HEio0}seU9HAfLOjMb}=Ey!YKI zg(g^#f@W^1v&Hz(sXW&T?p&U+GYoXO>8~Y$@6M)?kb^bbCY~5H>lU{^CXz7D&hu){ z^OFcL4)6;EJj&xE13VXxQ_tS!oK)g&%k#@y=VTcjCo%9XFl?S0pPHOnVeNoUWmWFu z2SAS^Nkn(-N3>vho15}8NYjfHujRA1;7*6_LRxj9i+NI<+%MmhXaROvEL4LP-_2tT zhLCP)#?|>PzkW$HV0hjkoMH}}^?6AGc?t)~otXsA>*HEb?LcYgp&n4tVsW^A<2Id; zpM=lO?=K+7s#++JOWa-gsw3WQUR0@^nwhvN{`FND7h0er7YI!mU@c0NxtI zPo#`vtk_mc<61s_+TiMHE|^9N`!hBzK}fgq$3ukDT=VZw1Lr5v>^^FD@nb&;h3o~M zlFm|zl^-dJQ{-HfW%*ej9v@AXFFE(TUMefheZhN0uhHez4}Bh^#%#-`r}%l-*mh~x zl*tMe)bU6QxT5lqfj1Cy+@hpr3Tv-Tg*_{1m&=zG^nV5(}lb!B(`vm#0rIj|2lE&ts0;jnA;xj zZ{5;2)%S#}reyLYl}N+p*A8$STvKv;EyJ8xcm#Ljz=iX)0@?SM^~(`?kAUi;J62W$ z7~Y0OIWC|wx_@B6q9cf~r)MaW*QoLQJrgbNF+-}olz31gSdyo5gV}Vmx@7M~?nlnV zo*2Wa&9#(vRI{_6c_X3^hrNa)uB#r- zKit&Jnlc3$&$^AwBl40>A__8nImq2+{dX^Y?mCw(l1c+K z`*C`zFLmta+8rOi=1Vm3K=)B_T1==?e91q$Y+qpz z`=ef!xeci#^vuEZb=@nbGJ4&zdf=@D^>F3Ld%-{oW8Z^hqdW6wr#|~KLtkJ%GqThY z38A!1{gET$yMw~W(wfD}E~;3Wkc&5T9S{5=rTVTrKUjO5LC0y<$kvmc0ezQ)r9;^K zRtzct)#7uwM=Euw@ioZOtq*v431YnjWVmy%B6SwpdQw#Iuooyyq~UEpd>Z1*Z>{X? zlELHDiheJQh#KGVdD8Ux#@F^SR)%@pmIykr;!akm8TcyjR*=B~Y$s@JtCr5>aJLaz zE@cBkPxS)F@pJ|0Zw#Us!~{*}fNX#)i8Fp=vhU%7Lig!0lR5~V8DFF|A9Y>rME){^ z=zXWgh2;bHpUyB~QR5$|9cu+yxB0CHfy&GFmqB&>()<78 zX}oj`33h#}c#}|3tlA`SIa_!qq4?m*RDSHGTBl@)Wc?~*dwMhOli%Te6(CIi3V#wS zyy)f%wJk`vT#=OO0gc|XH$ArV->_i%0Mz3q6pv+Z06Pfs7EKwRZHjNe?1<47- zrPpTti3sqbn#41o#8V#6|2Zi&TZHfxB)kh#6pnF#w5QC{(kJ$nCBN*AIu7gp0-_$0 zT02pr)9uYi3T^D>icyB!p56Wgl5DYA3wTg*`YjtPnl)`D{iDxwD3)Va^z0Pz>l20| z6x32(KF19eGcA}qValoE!?`Nj76!E48vRRN46w&Nt!~$dxxebeO zI<@VqZ5k*-KMIiG49JsDceBpI;hwMu`D)J1Fk5?4+`4XTtlJ3A#J*%|N{MiqM&4n_ zb;=m@0gx2KvLfhLRr0;9nvps5Rtrk7X)2A}#2?+`pfF>Bn6b%ne7w2GS*Iql1Va}{ z!N-1^*wD~;*1^pqxkV@7KxV1LOwHlT)1qR7iRE_9Z2^+$PjYG^<&BHUM^rzqv!1s6 zNVrI4gq3=7@$&0K-EUfI5{V7RlNEt8Uo(h^0_3vuvSRDY(K9w;tk1JN<#=uK z&=!0={rRjo?X)U1xU9MK2a(#zJifa9sp2%0HGM+g4+ZKddfvh)nnh!erRoi>!lf4Q zrGyw?j1URZv8JOll%mEo-ru!mbF6{|G=Drt=iG{x7ssyVK0xA5F;m@wFo)}=r#n?D zTLq)*Ibn=IBD(|$`|Fl2DzR>!mJR6oveenph=DO?F_PD=YO7DO-mhKBg#3AuC_v6o zVeBezHwpwY2IQuFgX!!Le29(((L~ZthDvgBa8&R6KN5t#MsSIrz@OhOJhrs3mRhngX=39naE(^MW~A-4-$4n3wO+qCRUtK^kaM)`h;0dHtH(aiv3 z*Ey^9A+RSYN8@TzH$W!{rk!e*7~$$~5_A`^Z#$|3C85o|K%UgH%0r+XB!38E3Za_Z zyaW{zOQHX_F3VqD-0OmlUSwh)s~5u+x#QOYtF{vyl(O;mWhS%*{zdLCZW`L%(V(Ij z#du`ku5(BX)D^uKDS*ZTA?4oL#?2Gr=MC<%ep*jp^!74Ri5L2Hh1BSBXk>&I8vPuez z`lXf)Fvu5-JAk2+!6!|Yeg_YdaJf^Ld8Iz=LBmT}Ojm{>rImnq_E<2Qjs&pXKS z7N>YWi8^MIjzAo;r25yUz`mA|YtM}u_-nQ3T6()?5K#a647SqU|Je8>|+`JrG3dQt^L~UR(WkjdDXX>Q_ zl)WyGg+zV4qFxQ1-7|R=wo${E>HEqyO)Icjm};)%USPmhcI$ARR8dqv_wtG{@PdR? zf8C!q!jgOJ^u4{XrFq{5EvW1ow`i>4m|WuO(XFxU^_2sY+bb=FJ>hE5$pFL~jX$!__sQKk+q>Nqv$|1(PMNgb&&A0`g6uIlNS z9*nahqdXF|PIbJ3?VKZKzh{Np5~P2=yHh4Muk8YaC~j8Ais%fk18WM`0?U4xVr2Zz zGujkEKL*;u4ML7dolBMSqmx@NC1#V)`Tlx*Y$4NB3|YT2u>3u8A%;;l)%KaF>DC0R zl+FGDq|~*=-H<`(E#LMM%>@sq;Iv?*ih&66u8oH?Wv)r^_4s8Fo;KNKCr2fxvd5bF z-rt(l%1pI`Gm)h4W1Qu9jGZbp-=A=ot2MTM4}w{R6vTGTF0*l$RSJFXOPV(wd=^hS z!l6@_osw`y+@`C;D^qi^&pOd5CXr+A6hdizFk`5zQa@@u`BZ-qpk$uvPm$lOs5cV8 zKYg$Hx7fCG61dI|BIglv-`ULSoo(7`JLtLp8e{AnoqC$8102{ih|6Bl&!Y*G!(G^hV3t*~l55i0fsZxUM z`CaOz_o81_czGRcIf~&skmq{Rk*cHwq|L}%1Xm#9)TEz~1OX~~m>v4l2g$M$n5wzF zeCxX2hi@M@z99@mDs6kC(QAs?ioLrn7COh7m@#bt^21z$)7CX8Y zdAO&nsNmc=&^6QMMJO!TT2#Uda7mDow!ZPRstqT5zt@y(-I>=Q^%M<*U>J)y1X2_F zWdv_FW$n8fUu(aNOcj@ubEiLLdZLjS7W&5aSwe~?b@SdK#?-!@1cxGAn%Tt1Wxw7b zCBD}#G34aiYcTYt^{3Rrl#|S<5)KAi1SRYY*2iKUd#)vdCvgXQ9S~$WV|!yL8GTrl z;b1xXQ0lhx)r|=aYlv}K z&ThJ=N{nfFzXRnuO_g8G>wEohP!3aE* z%My8(I0Ij_l=#jTJGtGvnR{9&!c7D^T0Q8YbjmjF&|J{Im{G;R{Rh-BvagjNPniuE z!|0Bu`!l9i+C`oGcSFAz@EYKQEAJ=Y{tOFPt-Jg<_Y3OO-8uk)JOL@Ba1A?A6tNi! zI_Gs8mXh4ir&G6nW|uxUu4MAg$Z$z3dPa)}N^LKKLQ9_;Ha;2z-QH8L*wIn1omd6* z3U|=U%|t&Hpo+KCCBGWx-!k~+r>^bhS9Yxs8Mm3IM4Hj3^JcQ><#6^%qPfxq^wzZH zip4AZxUi02)H#g&z8uzwzaiMRT`H?u(c*srj<^_H9$ai1D`L=%0e7sjc8XLii*l3I= z?99k@aV}&po=T8gA4Kj3K}P2O)Y)uYYW8~&3w7hH}C9=zonbfPnUPV*P5D96o-m5ldfjL?bu&7d%S* zR}=B-5OcVG?PQ4HN*0KFg;_sx(AtrJ<8DM9!HcveK9nPctrVFNr+q+*G&5A@Zo#Qe z+T;se-d3E;$U^MP@7Erb|pokiS~oVd{C4%YbIF(akt_6 z%+|(KWVDfBzTCn_%9g@Oj&NA@1hpIh6@-aJ*Ot$`e2WzzZ~i84Xv8bk-#%bIPMI&m zK22Y1D}(=x!fUXpZ-0-BxaQS50BjPqmb`c_iYbi$C!LH$R4lkrr$rGGP4vR5yZVc% z^!Y2O1u}suDrZ*MZ8um{6Hs_NBkcCl!&R&5gwf|8`fhceSY-PeZ@T|p5Ij%*g;l(EPFclT|m0np`u z&ri*w7ROMPLz2J6{hTg})u`y}IEZ?!IG9#wz8pqx44<9d%D4W+Q~K?TeyGQA~!GJ3(H&?->oVvoI!-{DP;VSN6?!jfCYMGW7Bz z{5r(}vD{ohW@Tq`F5WYSNy<8v+`<-o8_qYlT?D~@ICkTeM#nNbNVb<7ayGhh^qHRQ zV(e5;Y-B>r0$ppmUP;lzHzalC#+ld^>E1H?qA&SYQ8Iq0fFmwlk}hOT=9_spPDktV zf2yU7)3S1?24)w3RIheLD;w6JDih}7ZMG}x>uR@$umK{hH}tvZ3hpWsy6<437=NHg z9Tp`9Op+P#Sy|fx-5gA+95@gbra3>W_{APANEFsymiUs0r}jTaeQ{h2pm;)UDKE@| zIB>jvq%*gUY2R9W%YR&p{mR3Ft~vOkpLqa=zutdi0zb>96LMlPN-aQ2VQZ<;=k;jL zSMRTE_*TKV=6wi|i)PEUk z_$1h0AumbN=;NObdK%$rPxK&RmnuUq-5!-&sMeKe@Lg^?oz0By7eS(__7e5f87Wv) zr&r0ah(}e%pZ119DkgUha!%ER)O@W_d%H%%D+%x*ww8UoC2qTFr;F#My-^XmlIrie z{-85)d^IK6H)#rF)#~`InRHwwvy%vBD+H=C6tudk(jbyov|eR`pp(IuQv!1W z)vMce$b88LIMdEbn$xCF#3qmb(!i=fa??hBQLX)vZ04+OGEl#weBp2Ux z#c{#9?Z#Ct6JZn>E)TV(YDF_q|!ck-!D3Am1F~#+Xx(UZMKFu(<;~;Fr8u9 zi`)@YpcB4R3D76s7ml{`5W-+{J^fIW>w|-L77^9rg*7WV<)4klrtW6q49(&OqZfRN z#d+LT)<%VI7qU6iSMk=L4m*Uk<=3cU*mwHG<++>+%@nu8b7v>nn+ccY&`$0lsX5KQ zE%4;oKDVrF_8S>F7REv^U9L619Uz$JEt)M@!n;7-F4=9tLjzf^Z7BNCwP8OkJ9T^Q ziqF;SdAFU5Kfm$0)RU7mh#&A%yPC%g#XZ~*h7FZg<}P^3JcEo}$P1D@lH9*e-^3z@ zY`i6?Sh+=ipJye^V$m(qv!B>|0bolzg%ihbc6rT2Gw~-$fY#{jDinz{UF1{}@R^a2 z?aGK_W>AyBfavwIscUP~?4Ttgfw5H`;SgOUaJzMfzKAG$veE`y16P7jXyv^R zI|V8g;~-hb60Ku5LgqgvSm|-_mlGwQhc@|b|Ogg#$D-*Bx`DDblc`pr*0m>R> zql85Srn0sMfL)LQnsM+xlQ4QBJ}C)qAQbHtiF_SN(U}i@H#dM@kCwlAP9L7(YR7hp zPQff<^I~`tf+im-Zhor2=(HS7X8TBMmO9?r68giw=82QE!pb*(=<}6tTiF;H)$?)@ zcmUDo6C&oKK|n&U|KiYby$G{WAF|I~rk=};ZBXRJ8dhn?-xGBu%lpj}=L!wMh)9P> zEN){<=2zOwURmOUoRrJAXV?TVvssCyl$ppfn`hs7IZ8q!mKD7Ta#fnz@s-}G=(V0u zA7urBiR}e18*9pRm(VGi9_LN^EdhuM8lc%L_L%Ga$N+M?{14+W8Wu7BAt=UDE+sk= zvBi#C&LE}kY}s(u%1g6`^7${_^4TXj+^*r@b-V?LlXb07L8SF3tO&K9*w$J0RH48! z7(p+*}v|fNnBIY0^h-<=Y~GKDlY%w8|FUJC(FdG1W5>y-gf2r9^JYFSmd< z^_Kto7&4f3FN`ji_jCy9bpZB zYKX)imoN5;?tM~_^I&sqkvEDlrLvVlkj2Wp31!KdB_qqSsgJg=`30dF>A?$}B1t(* zrza}511>%tvh@Ll3og>!cV6>ZUK~dv6up|<$n6=bUcfdu45y6sl(vgRk5l`re&T*j z5=%1}Y~+O4mS~&U$j%p*N}6n!!>poIIPWWMeAf0kLD`r>L?a5lGnVXK!rAnwJ+a5X z39izAsVTJz26NK3w<(xx(Eyhnp)F8#=v#DH7E;N%nU{XN>Eyt66~;7)mFIIC%zr9T zL10c*rN`8BNCFP}i923Cu5j}P3TQgo+R_5JW{7=kWBzxgFPU=l#diX1^)5M7A5wACMViy+2J$Cx z(iR{ip3UH+8%lWda=`fSo#o&TU9w*TZ~$&~$+AGL0vp6j)hd|Lc=bnyaLgH{7v!ds zmUpLdyRf3|+$x!8(c2~f(?*C$n-8GzJW>!5;5e;uuwrUeEN09L&kz5}?*{>cmSxtOI@)sKWJ_V70>77(ywfvQlkMe zln?M3go43pxBIIoqHx(9oo%t^;ypfnCmZrfoStRyJJ-###|AbEf-eaSqt}hr1>J^v z@(BC^!9Rdkj$--|3+DZ1fd91AiO|)rtGcfsQ}x%YnCmz-GR#e`t^56!gl6%SMLzlU zLq5N}Z7nC^a%LyVIXS%v+-=bpnXy(JmX=VTnh5uA*~Dz;RKJpwACse|B~Op|yXq=2 zZKugGt>u>qY$ix!gFLz3kFTzO$F=3*X&zpfeCNCltI%TtHL+f(%oShCf#?R?bNB(B z!3aKxQkv1Zx{ZrXMvDVE)zqQJtSl?Mq)d3C*fsc4yKXPJ3etsX@aLJ$(-qv==2ko2 zpGg_2I04Q>r&Vbs7(Woe17v-Dm~afEj(t@A)K2eI-Gb6sk+15OJDH9Xo2h( z;o{vm0EAFvc;IWSWo=O-+0!w`ms!cGjP+6V50a#>Ba4kXTq@LLM%T;VuM`T z&ACn2?AEx<@1XGkso2KXAb6|Fn`r;Fv((6H!yyE-b+<*XZ%|hZFF*KIba^Ph_dGW* zhym?$p5ft2{eu2RM=>BFpT-G?k|xRPBQQ~evWDp{9CrZq0UAmT{Ecn#OvM^KQv}k&kMc_1CH>fFI+630l-k7cGqg~ zN$^}gIi?y7UmvO(FSGBqdN zlLh76W1UnXf;d%)e(M-!hL)4j+8IZjQC8ny%l5p0o~ZDIdIv_VwWNl%3-&mppqHe% z0|)Wj9=^j{bYx~~l2QD~hRZdSRb$9!3sZZ7MWQmZ-Z+oYu$e`?)m+dBFTe=1kcG?~ zIJxs*pcNW=s#|RkbOMN723yuU^QP!^l^SED9Mv-%_cL_N^+bgsqk;nd{R+j5;Zsw( z6~R_GeTc(Hh*vE0ArSKL3_(H>S&yZw>b$Ik^U73nC@@6bAIZdD{Hy_X6s4$R;FK zt*POeqi3+#God@16=M`U!rVhPzo69B12wMRu?z1lln`qODf!NL7d5ZAis22ax{Np1 z;t(@;Ol)SX^OmDf&Cip#BK9k2JyX86=$aX>SkKPebs+ChHT%3ArN*0UuvEX+qmiFI zZk_0*H;@ROrOCz?9A`^!^=;o;^$PmdjKWJ#t!F{0tt2{zDI%N$Wm_K2co@&dkLsgrYDCR;Qk`I%*!Kp#hVS!Syqm_(w&o4Y5Xaq62SC z(;{}@mzJO%w8bj-EK(&`a=+hH&Z%32hTHDt&Ob;*LJr4nFT~aKj3}-6-l%d{E^j&K5PKi#kvTRlBa5$^yuo8fH}&fxwQ<{g zqHiNl3Xdw*ML56~9D_AT@{T~EAz3pe5C=i>Ro4?z)V=fK+vf$t1|hbB=*i7~W0;n< z)5;eX(Qg=6dNVf>vMh+5s-6mnD#C2@%>o(oA_Hf^prkgqrGh|xVfCbXMdyKGGf+}W zoWn!93%>7zc{g(RfFdU0lsN!}noe8a>JRnR6LE4kdBrO=`iwrGKZw*4EbQ~TSNi?T zoiQ|!jsBDqbK0DpryYyfE{i{c>yMF|E^ zHt$d?AdHneka@`oY#2w6q-}xuW;)Vzm%wAM8%M6V>wP`OS6{@T@zu0TbJ*@9?MAc9m+#0;p+yizh04ldyPppAaQjJ*%P}0RQi$aI{O$UGd)Q{BJiK4zPYmEGypl z5rF`q*y{46!$KnbP{u_^QctYU@==lUN7!x$pRkf;qM3xovIph+)@~Wk8iwthq-)p5 zP}a$#r`!Z7uxXGF?1=M;Rn(ZjPDZaN%(Q>6N3u`Ln1*F4! zdun1Kw^RHUWo3Cvc1-M2mZSN1)+5j2Lh_pov$w2#c`cHwPBOJ7VkktrriD2ohg8Qm zT4BA(B`fNdhUsjpO8Bj{uQ-SQ#BirB%=slFV3Bfpvm>BIz*}~ z$vrJ9UzW}2`81&8QPd=+o0a80f=afd3t7~SCuH>aV9v!J-Z;0CjE`N*#EDVuC?itx{Za@0NT&*Cwp%8`KTtR8~T#V`OA<-!pF`Rg+;X6Z}x+|aWAg4#Kkr%Gi!<6|r$)sM)p zb}@@yP@UEva}J8m`D29VlX=A@U9%^_3n3+JX3lyX)h3UtCFPX@wl>NK%=o?`KAP8y zBEf8}frM0nb}3ZplTC_`EX|Ml!ynza?Ee+PcNaIh5ijrK8iHK}7-ZI#8-KvibXh9h zU6xcXZk>;9iIG2g=y%NT?u&u*sq;FaPk4nBzJEJo-J+#+AG-x#xCwb#`iGgRfe9?Jq-ixB9 zILNqRYtN|>I7)HlDTF#}*P9=$lfgw4Mg%D6)2M+qrqcYHhA4iNOZ31M9j<4IsO(QW zW{QfPN-(wIWv7hQ)Pl>V6(=3t;Xk5^+2$85_cZjkt!jJ&R5zhMKPtx2p7wr3V|)xyjfQVxo$F9l z1CXeyNh3gKT=0+c=#TFXnc#}hE^_p57nYKmKb>BXBV<_j6_R(ly^&SPq+s0_wNQ(A ziv0#eBr_rn1lrfh<6J)Kw+Q#}I<~$s9c!-02V{nJa0Eg- zpxh-WANs;5J%jc}d=*tG_l+MSf+$?w7T$PF${xDm zn*O@>4vNj+x%_U^>XU1bdy&ev{wcc@p3Md3@30D-ac_E106(1Co7y^Z(VaIHT5^=U z%Jz9X4hz!M=v3H34dEfTWAWo{4PNbQk}=FEyc9lsKs6Pt!=w~KAInqqAk;S2>`bqD@k=zX^>Lfv zN@fISJ2(t_uZ^6Y=+1d(By?q~C+f98GiVWhHKYu z=a$?}tE{izaD^Dn@*p$uHWvmyYArM7f2WAXcHSc{8f{XhS6sx2I!TD(HRsrs>c$eq zD;TLajb7GW7aC;6?fIADz?`Q~6m$V0-MInZ0ph9jUQoc~9)jq5AxwR1@Vh8q9^HO^ zw+dDM^PHHFocqnr|MyZ&__Mbr)B&3l$#kSsB86judXjsfd+KU-5=F?1BL*ncoc`N>6O8ZLMNa z=xmzRE)~(Ly|Ip4-C?<6Qsq1ef}vWi^D&`z7$TIXVF*9fkmnPh?jy56;#73=O9xVw zxniT1jIiQhWh(uE`4ffgo(4Y9v~alN|jq#Ol?(UDj*u zDYi$7q;g&20{4R{`}{%!g{{*V=}PCfYoLmIUyax2ZiTszRdI_Nh)yRLO7t zd_Nl|E`a@UM6e)kQru5ECg)TwplJQf2HsG&^!!w)hn62GsI}qwmU(@86Z>;VY|_GC z`XEjbYKcYaSKYv+4#EjWE43hZo}M!Co?x6s(|noyGFFJKS5iMvg0Zo#jKpHu`C?f1 zE~OCl;v4&AcWhaXqq4#FOWG^CT=K$#Zk`L;3dwWTp%IUlT5G{aKC+GSd*mxVdtn)<2ayNcIb&SX+bQ&c@aZil1D5m{S=8~ zi-Cb*LvCS#=W-X74;m%TaDR&@JLM`LWbztaRyfu&>QrS~YB3SJij<3(1G_A`n>n@~ zM3q@n5j2%XOUmdf9kpJF*`}g~KTc>NsJfghe&_`>$d*vfeooIkL8;BK3NMJ<5(P9N z!b%>JEc?|*36OMfBhgi)`qiRil+O7G)yH{&A0}_=)`{~7A_=B#0FBo^g)CDp{_`fZ ziLtrvC9qOJgPrVJ4a*5rBDVVSUm`bfF z-w)(x&l4A;?6WzG=1~+ypL_D-=H^?I`>(zDx~##mOwsl4-1@GzBbGQ-vw0T39O0D( z;{I|go75qS+VwzVSfSoMCy#dlfD9%4FbeSKSgz$wsoE;tPC0GzEP(p+ic-|YFrIcW z%FR>J=+H|77A-5FDnI>stL-Wc9Mn~g$eG9w-D^;h${)nAPncc>7hZpJ7 zx|zeyCOi(86+DREp=b1%@A#TE>h5e2TCz5RtpI^cU4^mo4bxLOPILd|we>34SbqD+ z`1-n;)Ath>dKD<6{4Aqem0a(x$)@08-A1BsM~DXxIKCCb?S{wBuSY;RNx>8-vgS(8`;GfV ziy5GFg-gGEAtzKs9}H24gR}Kkf4Gl;Ys1plGqY%_qt$?JU!hp4m48QOl@DBl4 zXqqkQBxOeqFLRLv$(zJv%0F)e3%0Ld>votv88}$CSfnQ%@#Be5yHJ^G1mk_Id7FScdJYfN0r}g*fGY-3c+VJn0{W^ zc0i&eo3wm_)$2gzCIFgKL{Si;B*v4gtF$Fnfn~O1`EJb&Pq!#-+ZphHTc>_nL`EJN z6fa%8{C1zi!T70c&tQ90(7Bb)0*0m1in=%Ma*8{E7h~BI$P{p0<?e(f` zY{0r3*|XDqqyw!q`D*$+ydGjyQ$KM`!|L(4Xr^UEu7Cesk5S)tKuGB$(l?5{P;z4~ zEhMP)c8Gif7cSW{V3)Z`RsbY_xlbyb&`+{IA1U$y?x+7cntGcGxCRM`h_5!SIvT>! zkc%R>tC#Wo;MNNl4@HCDMlNTnl}~Z!QwodWkvHXUp_x^-=htT8T1{pQ!fa#d8y!T6< zqY{zr4B~>B0O*w31rL0tn}IL8!O}>tgWzokeF&z$6@0+g+Ld)m&f<8FU8k`6r+MiQ z)+U?7^W=8~r=4-b~?#=cOFDN>INVJoxc z`gAzB5a}w*EKlZqt11t(22wVr<;*0 z`=*fp9bZ=Q+HX$~s>oygp1-Ml~x@)trT(~5a$VZz} z@&wK*6e{grvn6v4->BD~)s%13vrvKkUe3#GBI3 zF~0|Nhf4_S-S#OnLa@!WhB?)B_*rB4ZW+8zUd(iK5d>*hX^ihF1BLyHgMOzWw>s1vi%8lr8`MUt)yA?z?vgnzG5iRep4kZ!(*ismZtG z!$3x%XWg#>Jla(WH2u6qnvT2ohI7ABVRCJLd0h4n9{29g$5?|;^vjKxcx+cRACr?P z0mMC|dZJ^GTmco7sz2yE(;V6P*TycP(KIQHOeQ3a1WxkS7rF}h7*2jVpkuVZlxXra zMVy%+|gG`gcO@^rY|ZgW-k#QWLa>}(*K ztJq}YCcd9k9g*&@IJv!BR+NF%Qx3Tb-*IyE|J`{=I)7qkrr$Pq3^E=;UP$el$F~cP zXgErgZg*CHudut)9o8TY!L0kPU%&Bg4Ek*aqZvD3*)dF7@u3bw7Hr_p7{)GrKO_~A zq4ri;@46gq-mMfVzvEvE%JbH~2B19y(gQ)S;1nYx?VVkU3M+>%D$wT3;OkE1tK9ev zgE3Im#9zt(Aqxmg^Z6gRnM%0AjmsA+NBmZmO|>r++rp+DUg0AY)=$rZ6g0(d)u{>& zp^g$1@ojd;W({{J2)@=Y8N@Z&766hC<~xBZA-H3AdPgkeA)5)0t+z+dr~80S6ajd~ zxJj$QSntRth(C7zB<>1`B}(EI{J-*eQO3NcCvb6tputKv6;TrTp|u5J@d0xiUQOV* z^(FAtVbJUI!9RrCx%%<2#mi%>mJX4TX-~B6#0B!!EAB=Q=lIH=jIEX;otQ@h49FEd zapb#baRY<6N8RKiI&hr$w$eCOpk*=TBw>vW{9?_ zzu_!Ti-{6G-ymDMh<(s0f)3eEa_eeGZ`0P?e*~Jh3DD`tS(n|I!hNMRJF5y!cGBcw zH)ru5vVwd9#I?8eT&B8AsPWmQM$Cv!bi=RpU~uuR6HvQ{#*z6CcH51-yl z&fqDvx>6Qz<&wR|YjEO@D6%BZL$HwTEny3MN^_Tv zR{QHCOAj)@es?bR zuK0d(ePitG$3(#3NvHJXTW>TL$=vKN~d@Zp!eue4UtW2G>h!hfBw77;S>4&;s|K`&VX0 z@{wrY5G=I4`>?yG=S=Dy?M(RqpU=NFzI}mF*SdK|x#L&G1sNKJe<)lZo$O3PPJt~) zn)`JodeWhrfBv*m39p9C7Q_rW7V9NK*B+@VZ=Vz5eB0d%P_4zam3DUBS68R*bY!ADZe9A@T(-YWBF@_g0Da%tW z*e4U?*@%hPr(J`B+0EN9Z9YJUx_w3-wisc=TpqvM^%(>4jj-eM==*M0jedygj5E41 zru$H)1`U4CkGieiJk#{3IKo_o;MrN#vtML|nyQO-^NwLVY&a;+ILXu#9 zyQ)4mU7gy1>l2s3nDsC@LH}-mxxry~SA%7@p*5m;YBy1oD#Ml2beeDH$|NWlJ_Oy! z_L1H8N!B3Je+atDpwzx>#rK?s7J;0pL(l##Y3LuP@1F-lPS~Sla0`O47T;y|$Nd{@ z7KPb4g{F)GKxO>3eEWsI6<-relILbE?Qd>+3G}hQl)A|PzCR-!2o4RKTWu|?fc%&W z`k8*6vk?;%k=|zgy4#JYUmYN;35Wn-FSJ2Dh||=q$UNwEEy7>)(g&uqT@BK4z;^qY zzcLU+f$Kf$4f0Anvzn^(0xSBvJ!wbe{W=|>0UraNO9(b62ygP?Smp&kf%J23pMlXu zv8+oOXI|~{rDm=Mg5&lRhk@bah}xN`XC>Oh0l;Fq5UOAN|MKPp)l%hy>tj~Ca zF>~Y?7jt>CvN_h>oHo30+a~{TWI|z4bJOp8U;m?#!s7U;Ur76>B^YlWao^*2U0cgC zm6wH1V?CFLe?6g%;D1Sz{w}(a%eGfpFxSAqLyPt_2wGi%c7t4Se)@=pR9@HciXHd6 zhIdE4mYD=pwqMDIvwoo9jQMPLd@XGq%z!M5kD$U{-_Xp^1j+UKROQ$`)I9Kb?qDsW z0M?aKHil{$z6azycxJu6ZT&V0`IoYF_bX-8T-0|1XFiF%lV?X(#~2DU-_7+LVrVKe zksrA}JxoAXhpqUf+pfwIcXvQCN_>x6I2MBkLzc#Kw0Z2_d(`%*d8S-m?Pnb~qYZ7AQ7+U#7Qn#r_6#LRt6pWuYbsM*(&o87%D@9sbVtaiNVV|1Pjge3 zn|+0vjuo0Bt9YE6bQFthSNC}L_I`#!wqM|u0kU4|H%>B@x%uu|M>}`rm%h- zzwK&HECi)#r{v72J=%nr5QEBz3gmknv3F<)s_mSsuNxQui7H~QCG*Iyv6a)?8V`2mPWAfhPeKtmZyFf zqW))Rct#|Ud6Z*+Utp3rLx9TLiZlE#o@bODiH%-oK9n`kQdH2g5st-;W$*aty)RLy z^<=X4yE$@Zf+2I%w(|k)cxJzQQ5}@~sxU0}PG0yh@%V6BiM;Adk%XXo;2zMo7RUB> zPuRXd=(Q7{>wQ1>GVfFM+d4IYGDIFcAjqK~y56?M?>)?;ULa-dHZY{1>P9Cgyg%rx z=;ku5kQ%FQQQ2d#z)hScl|nPtUHOP*55a5uhvdZnX~DlEjDpWt8=e2+Lw|jrn;g8( ze9+U=An&6m6J3C$&{Fv7P-x`>dQ4Yz-J{BozuPcvTwHIhs0!Hl8lQwfN@v?D^qhIU zq-@q8AF^}p8l`I72#9?3`*MZ<#XJ9L7>$=t?62Sck`YdG|GB?ma${2Bvib3K4$^ex zFw4Ayxs&w<_>Xr2lI_qgx$opamCH2{*zsnzL;Y{R$!qWF36^o}m7;=WrI5ukUC772r9ic$a)Uw~_;EQ<2`KE)Jh8wx;1^ zUT1M00a_d#Yy)w_lAu3 z>HEy0j9CKzRQ8G<-xkb|IZgybC!cwo1ni9M4mHEpDHF(`3rd9VRlx@;bmA7u`cCe3 z+{Hnucb2|pPcFS3WaO4!0sN9?sZ+Ykj8ZCYWq&{xW5f}fT8UAl4zu_&% z8QZrKBA?E!ByNfk-(I?2BFTAGDe(X*?DILfZns$_F<|+DKC_ztank?xkHE?kaq%Y{ zTpm}XD+Tu7ZYDls?o&jF`*j(FiF5^r=R<~;T(ZS?m3{`DG& z^&Zcbz(;_77d#tKH}v3`t8pPrO&dKXd&| z;G_?4$C-#^iQOIAJO~XKZ^4(7~M~p*Gk(8TOSzMUIzqQr%2km&qjzKf`Jw;T1pnny1Jh61UcPtrr>q{ej8NSvuUkfluFES0TLs!EyGO6j zeAH0+yi3E=xnzQqGhz$8qYemDmIoa|@&TYme0nWeHS<)}>dr%o7}d>%c^vAKymVy_a+V4UxC ze$G854ioP`3akiU7f8zF|YgAhW1yeQSSh{O*DHzK(O^@0Q7XpXA0%kGj4dyZMf* z<@j3ML~W4_U7n$Uf8+2~%xpsZj53XKu1wHsQTMNb^nbdMGp>OV5z;E#Ezi63fBrml zQk~-o&xz$?4^9gn$+^Jf9PjrMZhgvBgJyOEr)GV=J+B5=p!(;g6#dgoC+&q@-8v5e z>Exgp#pBj``};rtI`+M!i90`jB9SOqJRFv(xJSQuUW|Cq{!U@%L8H*4rsB5@F7!ja zV8mqT^NN%Bj_NWnvle=FPa;NP)vY$4AQye5;4Lf4`O;h)pw8S z)gFS|W2ZK(X)5OJe~*8O&()kRn+#WLLFVS?<5fj3KU$3Qb%K*c*M0VGbuYn|urQhz zB#eesO2fYMA~RGyo(eDbx&_0hEqxa%By@I<$%f>sejlWo5&U7J73OWMgUiti0XoPRyRlOvDHO+S$J!L|K&bB|{^08v0Jg zbc(`2U76iLn{C|CN(;nFuFJ@fDfrl=DRKBKLNx0P^{8s<|_| z8R&SZMlK{@h0WeQy7&9V-rTZi4(qz0r zw~u*MO?K)j!kmmD5U*(*Xq+%!u;24?GIvxmM8$`~gdvIQ5IH;~WI}Ea4mA z_N5@aywa4#_|c}4s8f96*5z&aWxsf3g?}F>{Ocs|kPXcF%5}E(5&C zGO3n2CoOmawQixLZkI=o$jJ!?FS|_5a0Nmv)c<8>|9Z%O4P*ZCYKvctAxBN4azn-Y zXGkH?58~b`i38Bx9Edp2Z$BES{Pb5_eC^6L`!cU-IJuu`7&CrmIN|iW0LSq> zD+QYGHvl`QD3{UOS`7Di#{n?HvJB;@TtPE#Q%eMmnf8f~*5sF{qz6Mb8A+FC=ZGC@XrvKs4E$$w6w^{JDURLeF&_XY2g%}p}p4;{B0-+r@$G0QeA4Vq0w&Q7T6Eqmda+A z?u-u_r=^q(A*-h3y$=|a1H_@VDR66%GAZN9&eG767Rgp?FO^&%SW52?roUBN_VyEO z#RHq6wF~b|rxcw$OUk~xGa3dhTOSuH8KXB}({iz}{192b$2%jy9=3+#hFHm zHrgLw+wXgvZp%<`2R487e=v{x87={A?Btt0r+a_fMd`cvqOYaRUtl5s^_O2g%v>BJ zHf#q%wq$FEqW{4l1D(Mbomm|A{uO2JBUg_M1xRT=ub?l)pWS1X>Tjk!3{sDZLRf0+ z|L99v;7kAeCWeFmJA41w6T|;&5r2m|{{OTHiwDNo@t=Faqh{^}UenF`v=I;56+t;S zf&ZAvP2d>q8D(W`^ogx2ls%hqdyLv@F-WB)= z+1;b#IQv`W9nfl+uLK0wcg|h@;W~2PLQhV!-(*jtblg9Ilc8=tw;XSG z;eT{o2J$knHHYy1Efc(X<%e6D%oUV1sP;nLjBNIlwup%Z4lm8cUANTP`UgL4CuAV{V3uZLzh%{uJ?rsZb>(jd z=*vTfX7);Q?X&{+xai$#g$}-EFO!tOnNwJ9R5!M!EDKOg3rWr#x?{muO1S7)W<@+e z_!Gy(diV5G{{aG)*MTq9;cu<(J!JwC@BjOzzlWgzf6iV*oF``A9u2~xA5i{0GG}|U zrrFQPc{=tTTSjl!HzFTG3I3n_mlJh+Zl;>UDQ35 z5#q)UE>siEXE*RkDJj0xcrzff*S~{WQI{oZ5wgU0yu0Q-XN!XV1`l@J0A9rAEQ)4}3y2>|o7;6e9_Fm z0Nw0|np*OkdPbL7>iUg&1Admc_X<~KW~T&5g2M*+>3fD+HX~=8Qepk%id}DbzZQ#d zwKA&Fw_IW8OXw`0)M(N+?U&{3bnH$nfJ5JNLcP<=*SQDoal?w86=$Y~&WY6jT-mB7 z513wYsveicUGI|F`EzaF4Ld!;NBhR4V*`PN%#}!OulBEXxM8!cV$B5L8}!A(bx{L* z0x!YT@w-Y7cZ|tJr;=IKO^;J>nqN2(GdE1^$%s^nGV3}wlL{O6Pa^k2y|)aDvitr=6)8nR5fG42 zkVYg&8k9yrxYVF3=gnLL zbI00yuf6iK)~;R6yK(Bl_CYm17E7Dvcq4szh_y(T2969|2I^GhuRRF4%hDblBe;Rm z^sw!UY+!CX`IOu*?>gfMu9Saa-!1>C7V0yTBZ53YfaMavWltyUCJTpiLOnR)>(`2p zk$cPF7{lr5@WR%USw@zb8IN|L9P?m3vaOd_GfadJtv!wUt}mTdFDE*m7DfMHdEkHl z#e4s8IRUAb4s;yAz;OLA^y{)MdEs9IM-786(;=Yj^8Q9z4a$4fQ$FUr4HTogKrhY0mQ%tLMt%D& zQ~dUlABSKpT=idv0<9|%&Qa%CN6b77>w+q|x}_o3oi$uXYVXypnFGzU*uhv^S-@v18q_vPhDIge`H`Ajh?4b%4QT^UfG-%YNbGMEm1{)}3l zqtaxCFTI>w`1s50axs~HG+N3ywT_(*sl;z)RSta*W*?#hfI6PL zp8YNxG6)4X)k=XC>tY4j7{k+p-7rcNd42gxuB$m;cUB0W76@K+I=e5pA-mHf?0Wna zQonaUk;~KyAaXI=bN$rSr=z!eI&P+6S&BKJi4-m3W4W=^jFPxF>hl@?w{`us+aX z$SRMWEK8(qb?B&9?O_?Kp<#Z5p36M%=vt1RNAseHGJbJeXb!6G`*wF`*v6?p^~I4D zaqog3YC>A1L|Vu9Kz8uuywXg!Jvn@S)KJ~CV8{m3 zb2Tp2IpFQnq`W{4vMbs}O}olo>tTU=w0HGX~5Op=v#)_(8N zD9y*{t#1dl@Ipo>XdbjS7#nyE zz{*R5>G?>A+jj2CaTn_tVGt?Ron~?p!({KG>r?M&f&P_jdefmkJN+O-gS(YLP#cGo#ktMQjg{FO|G`6q5LOolRiMMHxEl zdb;kF4IE=JdJbDw!{znwu%}LbRWzH*V+Xw0mb{1j` zeKNl!VX2Z879CWU4PEI5kr?SeD{ZA9P=$EigzP5?*1z3Lx63Q`n-Jzawf8^Wof;j z(e3EFy2Xgrv|bC?4mW-*V(ewWzK9cZ#68E7Hm}~c-xIZyk-X_Ni$A7dUDRYXjpqq; zxXH3EuIGdwbmf1@^Cs0d`F2BH+t~ekXZA6E3F;e%uL4jIe0KvnsW_SGz8J^I-Y^hw zF+Z%wS($C}}&-I(57O!2-;V%MNsrqI;eLA3crf=R2FYVKd24LZ{ zG^!M^ zqtI(wu1S@7FbWd2;)eaY6_--3qe|EiJ_xR1lQpWTU+d{zsh%f3g6jwIY`JSGMf$K% z-vAIy0;dI{nhEf-qqf}ibV1Vk@it1e1IdoPH2LBJ!9I9Vjex%IF#Bjzptg1+&jIdd zYS-_U?lP4wJ<>G3cao0U9rJn-N^Ytv5ckUQD?j+*W_WY##l5j}9sAvELx2C^aLe-3 z9%DuVxRDN;CtqB{ARMVKr%#9HDwR37?elWh+T^{*`xK4|8Z{5RJ>4 zj7gB{X{YYBaX`8TX9E$IEF2mX*!g6MrypqhtN>aeD3F>YO#nyO)t(li zEzEYay8SxJ;X>D`C=FfH%!;Ltc-id`H!k7B0pGLaMnV7TXI_^cpr)#HEmf<%v(prA zurS}&!Oc`aQY$}Tu&R7RZHLHd>{NDi6RXm{q$;Mn7`E_^WKxX!-_ zfg>D~;#_BdoczX=XFR~ft{8O15RLjQHp9{(wuJGs+DV_UU&Y-|;>a=|)^e$&dhshK zz+pwiRQzLdtwE&kqsjQn&5k54T*M?2qaDV;EHR4@CAlW{Ygt3UF8-*VFA?F(RPl5pu46p7qweQPo6-%@d;SGWGG!Jct3dA>V3 zIzC%1rVYP8lD<9utk=SCsq&I%_xH?hlfj5$iA!2*xhgLmhRRxxRBE5OAC28C9F=o- zSgc|YPHw3(<%rdotkfI4^D@(YxUEg5a!=xt?XX4xw~0`P`B!|uS*SE^j;w$;ENFM?k993_dttn5rVx?0 zdibxrNAzP@9k($k8no-wIv;N+piVj?M12=vFnq=Y+YVGpxqXH3uzkTBG%tkT$7p}8 zqYyi7Dt%t&{`ms*ThiFYE?8HDU6_?y8?Va?o7cLfDc4;2h2V~b@tqko1Fhx>G+!F7KyTv!J%=IR~ z-n-9rT)Tb0Tm0iy3|#seKOe>w*L2}psNh<6tQ2iLhI?A=^Qw^ZvXEE~MrUWI!_q*i z*mL|L2OKLbQZ9e=%|=(2Tp2I>Yuzxy9MckFsknU3d26Oi5!b?e=C0L&UY~#~n~mg= zudq02frYzz3p4(_D^3(I_U+@#%g^vbf>Z#Z^%W3qdGI)T%xCJfN(FrHTyCHDL0=hD zE@~fb&wmKSA?*70>GeF2`SEG(cmxo4U6GcVS$2D&*Bbkn`@)l>7_H@sTY&BI5c2 zMJ|DV0p5KK>oNS?i|5=5|Gb6v5}?iFFR}$mDWw>-1Po3-&_$bS4~f21gOjy`Hu8x| zm;(N6St3`A#ErJ;+vzR;NEvdXuU?=_S~vb7{f*#7gcoR?LNSo|q2Dzv;_vs%Km2q3 z`M!y*;sSb3ustC9KPB`z?!J5**wGJfnYmp5+u3+S1@Nr#qSnCm-@N$GME&pIXm6u+ z&YMp?ihr$hO6dS{S8w6z{4>qxlpyp#t$e}d=dt6me@(6ndW$6)i_8C=t`fW8|AGkE zVz&vn1>gSRigS|tITRqb)RE2N@?V=vL}+vA^HVd%zm^DJt^wq_gkrIa|L+U82e`1L@sP*OlvO4As)5d2;w8MljluEZ$K3w}(O0fBedjW1Y? z9_Sp1l3pHNj29afJt=ue%62Gb)*pYp!x-cDZ9gqc+7k@lLO3lHRi`6I*^nQOmKv&8(O6R7cQX8{6UEgmr8IiYUc`J!+@WhevNO>uSII|CF=?vYlT}=pVq(pDTeA)vAv);SwY)L#A;r$~D z@CFPFc@}v%czlR9x0}Lf3ZMfe@*6gs%=F|zsd3_c0yP6o-4Dm*9 zUkz~eRZ5J+JvEFx7W?$mlAi2mfS|^E*wu|mkN=qKTeL>bc2>F|+nHy4{I|plwn{eM zTcl%KSX}^1sVMS8PY-ANFOSfLGC zv4gW;O154?vI>rmtd$Hr$Z34HG@K6z|p>m%(#=hgGnq7O)W9OgI!#dI)orM_Av4O4gqvGGx-$R8bC z6zG4*^>bTy_yg*7p*gVYUTYK}E1x^pSlIAjPUuZ2@9uf8?|%HkIDfLBFg^Y>8I~Xn zBOqVTbzRAy6>1&IMfRaaU2|y&ucHgy zM#!p?NIc_wS5#%t=06fVT=t^pVwO6VctNzpf(WC6j{-H-p2;f>)ZA=!rrtOgxeg;K zo@SBWV6}Fu5*ulUsK=a)k-!)u&jUKW$ajfI zbdYl z6@td2g$A2(j>hqFoAGK04K$=04APnC$68F?b$LWrhcj=Bmo;=zW<|ZgMG9 zosW>$5!n8Rwz5ZlJJTIZuRWUb1M?eB_v;-bkwp#%!i4e9i@%~O)I?KH?&}P+gZAhlm zvdZ`j0pE`R$R9mA=j2}j(CuwbuOT1M{|;B^VAVpqeqBks&LnOmU$gy|Gb9Kp%hj9b9zDr51a0QZ)F zlgvykFJtclo7+JkPYjN3jWx_}+!7O-m6e6f8nJw$SL@KZytg9vnw5i)-%VW_bBNCt z-t_39_co{zn_AdI4IOWi4m0zjIar@&oUF11jhRMv?j~x70zzze!=*hmX#s9;hJbAh zK+k3(GX0C3uEcdo+Q>eI?mOjlrCfITcW+LZ&j_W8rYGqy8hFfPE{4UC zGt0v>hH_Qw-{2JMoD#>?y13HB*^g%04vG*La$IMQL|mEP2OwbF)6&l>MY-wjBT(jh z9&Fd`Mt*FGa4qz5E^JZn>}qLOu2hFp#zZwenU*P-798S}OoMA9oU;q2W*uN8eMf-r z_Htyg=(MMOW6<Q>@H6$)ESH_8&H5`+nVmr=$QBr)ccg|uDD0>Q>_Z_ym|_wK<;I+@uBof z&Ju=m2DKM}?sWKuDnKSlcB9+$&s1#!)iKF)OS^-TX@)vUfq&FsgniNpx!t*`mWw-B-eng=5d z`;{9#88Pj0`m?TbzDg^}<2_9siKxv}ewBv9w~&(_lckN77cqvs#cOMbYD@3;S8MIU z$Dsq?zjx33AyRX}P*jh>RH9;W(Z`o~?qipuQx{u_4Ip>$$nIUaF}O3@C*}K*7q*Kx zhm|0M@Str(1XUc{R)k3)r3G#-_K>hd9!xi2Kj`5$*g%#I`m80CW~(aZ+O0kkT>g@( zKY$3e*9#l3?&SF?Beh8Y!zVw0+|Ur`F8TAxkO&X9(HiLX2QQ=DS%swiy6m)8z#aqO zG&^&X++34ndCs3F8tH6R&5%jX`p_Gz@wd4TYV4r1KJMly&(Pj?KC9xjU%fW?y`d;r zCkXDd!Gs+75GGfiwHWJOJ>?NI?rY7F;+*vS*pkb5!Da{bJ>sq*7HKv2dhK#!`3I#U zijHBV_e7YDX!aN~Tp`4EiQn1(Wz6D_gDDt%i zzwnvQPGPla^mD?Ync|}EO5tOqPuz2wp$(7Qv4Qa`KETm#+9Ti6g8O33lYM$7=#zii z_9ilb9=ZBl`KJFHbnN!|Gd`kXjB{CoE?w`7~pUQUJ8_{ZX#?m&-o{Q5%WdoJua8;;gDZ?>eJhMtP{?(A%u>`&zd?W1 zUcGhqnC(#h!D!lAxr$D@1WvyB(Kg9Ys;W|cP;<6R;&ML@jSmY)sCO4JW}fX$mru3} zu9`-fzKpx|`p|lwC$8|OQ^@|L^!PTiZwh+mx18yZzn+lgeJlkl(+4<~w~~&I6Bha(5zd%W(?A`7)W?r)>8F~a zRhrg!)!6RSs}TPS8q`fYnJpFZ)3FZ@dl;N?$ku%;}~7osX$Ux2BDL_ph*pwWaB1bZ9J&K@YXDD(;mBx$t#r@ z$Z%GS(~T@fh*#fgpnZ%wo_C5u|KzX-lLidWML2xM`6Wa(dla1RP2Vpps%Q|$qt2k@ zG3eFYKcgtTxITzjNjVjna1mzo-OALQo4?%eejHxrA#4W58~({@FXRDEvzL8kpwtq8 zh0)@5Y*df(vQ2!nQu{*q^cZ13w=r!i;qysIGr+jWA@HDRX`P*e}sQ`U_4-DGLl4I{`WwTeVclRl(vO*gbw)trL7H zdCa>5Yr}`BUt~u#*I;d~xy*=|ats_P4!gReM`i&eMEC2CjQ0%d5r-df%bK1au0fm& z9W*?h27=zU9hD-HZT;dKc#q?_9s&46<$Q|E3%8h>F@K5;OWc~X)4{aejjW4pcQEg; zZ5m4GyZ}k;;eP($*VHyHB9}bsg5Thf?GEO!H^*AwEy-1lnQ0=6_J4S$xFiV=Ppx*7 zdgL6_y>h~m?l>E?uYXr-Gp`=?n#TJf#B0UfwaVN;T5lK6ppq<65bSUMB8J~_5eMI( zvN(VEQ884#35mjS<=a7TfQ$Iiuuvw~_E^Ix3N`+dXhGrPT3{JshOZh_!ZMRo=%i-o z1Rg5u$U@WWoN2z|8Ytv@m6+-%6^m%%=-Mn;Gj2X24BL;a9si<<-=M@QjGTJF-7Heb z<jCtizhB3DJ~Z6<5aA6-w`eZH3ni8>r9UMyrXXO z$%uJan6CtHSynd{xtdKlkQKFS%je+(8H}89mXt!;jz|SQTwP9;rY6jVOJ915bCrTc zfFdgD<8xuN(N@M^=I)%3KR0FK`gkrp1l4E6%<7$53Sij|IIo}fwXAY^hOugSf9rzU zeipWbSX;sElYIhvLFq?W#S@dMP#WOOub6SLP5(i{n258mrXs85StWM*#IUBJxAAVf z;fM9Qy3nG@bXZDwm&nM$2I|Vl$7`o5j`}8BD302opaz}O$$7?m{}JMj3LyN+wQs#CgKMLoFa#HLlWSr8M}SSpR{4GLVS@Tk4fbO zAF+QJ`?Z+x^%Usq_+3{eLve)SvBxmOB9D`K0?c5d{aI##L74X5FBed(0WeDuzL+uI zr%C4GosrieLY`6{iw-(t(_|FE2cdVyH*5~dvK~DjE?f818#^9683A2+chem#qcD&% zSiR7YWHSFK9@3mCY!yWKqs`zvu_@gVC7cIqoWXGq2H!~SKl;lrhEW181hDF{}A4*i*@TKuN ze9QPm0XE3Dw>GSQg`ybiY`0tzI8->>wOca+Dj@~~$5>;TqkPe~{rsSQ zaAG8A#=dZOX{J^0Y1&quBGub*$U3TGWde(rIeO!h=#cwsF-lY1a3 zLwvq%Yov>9rpMlgUh9qLZM6;_%!$reo^EpezV(3N9YiLotWkKZu)CM@O|j+Jc4QVX z`DJSzOeJXSeHO;aguxPSwry;>9Kw}1D3?4RV9Y>-4d-3YDQ<%O$b??P z%j15cUeHlo8CrCZb;+naKlSp`%Lu_7HJFWq9UU4n;;y_%z!lHENTqZEA-DrSnEs03 zHh2$2+2Xp3xa`_2{IZ&)`XFZHAhSAWgo&NJ;pH{5W{R%X%tpneeLT0JucOtAefPmv zEXk+WKeZt?7@CA6%`eFYR`4)YK76_DFLdyEPL@M1X@a+RbyzW<9qr4R^-k6Vch))k zVq<7236;juiK*i$#q+4wxvbFxV~!X+^AscXsrsV)dXFcY?gKd{QAea$X_}-kLcz!R z6_2e)s9LU`tjEok(8&-@J!%oJ2Tv5icdUm7U!4TtN=>;K8{II)H?y^ws(_|>gOpO{ z06W!g<|cvKDz|dsgzV6IkUToBq%yFSldqKpB_1!E{-hV3!OgeP0Yc>f4#ldr9rPDn4kOwj9*W!PyktAGy=# z>Z4?xosK=Svc>qzC=|Pa6-xMwxD|V@KtXzY%6c3IKYpe!oKrk?-=+jeoX2$|_m>$0 zi)zKA*^auZz392uz{(|Hb09GI4yQ35v#ic}jVZ=pY@E1+oXP0%i}IqQwo47`8K5pW z1T@@$T@tPTOvq@|_v;gDzE6N{Nm5J!69#@hq48N-Z{|e6s$UNhswlp?+SsbBhVmgb|P*^XYX zQ-#6gU6skI!XdVZ!KNpLY-8(Grqa-InrFZ^I2tAH6A}jbfLm;swYgdgG?1@?$rn>p z--**r$>R9Lah}eLo$aaX7ey9LBfCLxuMMU;k6xNkcPM$I>tP$>1J&YO;X4o`0T39? zK5S3+GQ%!un%`-DdSI7i`i3+7Wt7#ZKx+-mUV;I-;&owDf3~Ic35J%Ss}-4VB%gX-1n56R@WE64A87J0NuY~8Wgr)y*ymyCdcul9hf+@j5I+@xAl_T7#0 z#1DCII|`Kw*-d64Q0oFF_XXP%Bs|3tdFA-j`FXcX8VH=gYionKlzcZNL^-{pya#e3 zML9IDW7j!kx}UZnlfMp5*+YOHbk&#(=(*Pl*`HA@e7dx5N*)JOWcM5b4yHvOhSpP; znB&;7fSrWZj7aLdKP&kA;_)b5y0*Lg{1nu@(dl3<3{|2UoD`PR+F4jUCLytfk~CP6 z)MO~g8`CqHU&z0Q?7lymu(VG(Hzq*B8V!QB@6}I1cHL?XFITo4LKyr;i$4GI#Bo2D zi)HjTqJX2V2>Z9Hi?8BhKD6@3XsZOU^)oDm9LrysX_l{ghmR!bP=Zp{TJr1kXlkgQ zBSIjKrpUT)1=hXs@HO>>;ZIfpml zOEZXf`!83H0lSiE=(Nv{JE?zF_#U+GV;rnr6D9_%8+cM)7l~a$K=EaA(ASor%TZES z=|Vn%QMdtx&oEIx|ItxzLQs=!^J!J3Ga}TG@YLen=M}{$R?Xch)&bA-^@_g5_%3}j z22|v2TJ)NHAv-vIC zL3?t{-vI$SAZ;uuG&6X;l3k;2VWp|96`={C)zC)`w&V5EB#kw*HV!T})n;|e;L^v773tLq*B2DC z@5vuGF2qDcIK+*c0(eHjjT&vBs>~Pi%!63Nw*Z#vvTFYlIHl-5vr0yZw#x_3hZTk^ zqDF5Fs~Ew<3}<_V0mnKDYbM=tLmSpmf>MY1ZjZcC%7OSQN>KV~M3cs75};=o&6Cv) zPozQ}Vk-M#4>IGu#}dbI?w$x-P!g%l%Pv@0KKP#OTja`CF4eVHK3XR1iSH0e$X9NP zs4@!f_=B`aV@UD$^T~bF&lJ1w@LuF#qHfd^rL|EZ&}J>TGoJ8N5#gQ)za#+(c-nX9 zIc%mB0;q&|MkQ`V(Z(WhQxtho9Ran_oO`%jwQ~QG>y|t|MdCMiv9aPrL5?rZFAbp~ zO$v-(D4nPF*2f#$uM)W}`3sshr=&u>2Wd6EjbHAK1-&u{g(KG+_470eZ{@JC!i@dp zVt+xgfVA}h=#k}xr#j5sfWPAQgRgvE#Wl9iYid5&0q*#oTLj^J5CG?WDWWy6c$`() zL+_0XL=6(irY{zFK-GN1rUL1gjtNC}V-0yB4QrFG9^0$r-tTZeo~)Nnbl?96*F*$G zr++s})90@d9Rdg2cn1oJ>eqbX#CT0YYXbhbI_^kyu^=}$cfVCRS%lQYZCmdQyR?=v zw*6-6z=wd5)cI{jM$aH?DTt7zZ|{<|k{Of}2*(JIahDY~KE!Vrf?@3gLCoE~IeN_N z+RegNWjZ!rzS0;qnRaU!<~?I1#h*J^nvq-?D`ckwPKE@x#1Y|N=NZyo6UcdXjQLAqy zP%Ca?@M_VGijcMhY_51NRm~E|u?$+mQqwf;1*RN8Xp~KWKb&lIC=2Mo>UYdLg%3o& z*T#We^{jUJD{ZC?AU99L^&Dioo6{Z}hGAJ5{Z4^8e{^N0ThA~D zYM{13g|(c#2hIh7z8oc2&-wDV6p;_DNTa~EizDx81LbaA<-&dGXuFtb2)AFKLIsK( z3X5r``1zjIII_;v8Z92QY?r%r%)JP(gvLdDRo~#egY!Gh(jkjsDIGnZA#7?$ge(5F zkbmPaI{swEy6I@YM>063t1To!Lb`uItw~S2-wGU z-!Ltn6e%Ptq99uE>D}vx7Hq$}Q15%@qrElUzdzc$Jd`Q#vHkIVs%^dd;gi}vH8LEuh~u=n=z z;yzGeA4u<9q2xKl2!PW-s$&$zr21uZtUDV|5Kf}Jg-WVn4L~r}c!3_SX|%G`JDjah zqDkc>0G??Ok0H6I_h6|^hGSqu4!Vonux>r2N4=+$o=X77AW6ck4C00|g(hJ*7m8>+ zDjDG%bo}E-$ZwjjgnkK8+~j7d*<04#W{ZK+9{OgP$-V~j{Qbi_*S$TlnU68<%DMIT zLr?8$mul0HuMTLeVeWmU<;H|^$c84Lqiq^*(CH^aR|xU)tTpk+D~Yfo*%%o3?D7X zeg57^CtU52ZNDd2kLX=#Fr+!aP6qL;eA4w`C*oN4oYiSTEnLW-_JI+3H0&O9Y)qkc zUgABhv)l7TBvvY%vgy@?dq-RToRVjXKwK_Xke-LB4~@Giza-^I$Cx6nQ~pj_tvq6( zu~7_rcf(XexzdVcXBY(qg8ec1ID3~dy_aQ*V0xY(7GJ%Z$*~+>c;={%#J}dLPa!k! zx@EyJ3mJnM)?d;}20~f218xB@k%<|{{xH{Kt3J&ll}?aodE9Z`I^aeMYV;?7!me^+ zXusC?4H+Ms3=yjh6ERp~D*sYLK2o4fEKSXgOCR9}&tK&&*=>0()!lIogk=DfiF^$U z^%#1j3Zyao8(t=}N6&XBfpRD*L8_IX)THT;oxa^6ciJlvb59zeoTztMBfwmpBtro* zuWVRLqsS&stg31@>svL>LgCwNh?@jZ*<#w;)?>cRHS<-;c8V??5)MSlAFn1w7#qei zS}yL7?zi6kB>*Ds;*V-!S8zCZ-zvKT&r|8S)Hm)Y8lw)`W+4uv%iRhR<_9V z$3(JdtMGwm?o3v1*xx&JwF8=6JlIy^G7wkX%nPK?<0k2f*|RY$Zfp-pHrc(ni_a$L zwizz8X=G76aJAq@)?2wK7B{PSAOh&L?3J15tZ~}Rbt>#-vpekX4t;As<~$^;-iyFP zx={OWYg_vGs4~ZG8yam!WOmQ>R?k$Cb#FV3=BW!gv*}yCi}2Wb>FTaJ3^0gWXYygi1A zBLpP0f#CEw0~%V9!+YWWm(!FEn=Po0@!HIL-X}f2>^B@~W3^UYi=L!5G{!CL?vj^h zYWC;fA}nu2&b(H35APkWA>!U`3Ls!e2P;=ZKt9y>dppNDdp{{(U|wjxso{Qla-6V{ z>6}mMU!Y&_D!(xU>sS}|#BdiFECwqrd#K}}S>lIlErAXyTXdFBOQ6vj@54lp>qGhmiqj`H#Toy(&%w|(3hnwjy)5wO_)u2AY zK#HG|X#QTzdw1^uw?4gM|Imj+-@3Yc2W31c>9FfAX$4M?^mbG+2a5^eEiDO|c17+_ zVJ7WQAll#~f@v4?j$OZlBFffXUlV9zx}5o4lUYX<#REYEug#f+1t!Bq5SZmy?lBel zIK*XjidmgSldH*Bha7H-w;J5z2Sc5D$bDc4nQN!r)c0d_~8h zVaAhUD7ffkV(WQ4_n|-2`!%(LDY9EaI(W$a;NU}}7f*J-jeVW@$Qn9(^62$6%XHBS z(`a6jNhq!}{4`ytcf>f4YT>u>*%2$IVGx&7>{p;#AANE-du812-Pc$Rz`yTmbJt4C zoUT8J1>@mX!2x!56v`nk(4*h(7pV6KSE7T8M1C(_6QI46d;{v~XzRT^T40Hlp7R?a zzVh;PZ`5g`DFs~uHoSvhi5KOTRgo3^w79tUZPx;n7@u z)o7oiO5yH?=JJ4H3Xq6k#)YwHc8(j3{tMLXPdFr|k>9_>a&p^?fn7DU7AC9fM{GVc zmc6frGlI$K@|W;=pv~XQYr`uYIg|V_YTs$f;B%oEP6ZmBcr2+bxwZ0CGRrKU_9>vn1#C*&vJc=O`3XJxbeemmwoYBy3l+C&0j zCbYf&Ob?JaUxdZbX1c*~5+%=rPY2Cb@G`@*GVr&Xy;tWG^>E|{Jk#QJ$i?%H`LG%n zE$$Z1K1~nP@eRl%CF29poLs3&`~?>IE(tu$jbEjLn-t5T^;x zkCH{E=gX=Jy?s3nR;*@Do>!|&i&hK;5>A-sWF#I?7P8^?KI~UdqD}#Vqo+{LrbET%8o>{9uVd3*Kdm5*T4)TOz@puQOtd zPnr|I(u=2S85gF|Z+k05;k9i-qlXKxbVRSrOA0sTNjEpY7r%f7gV#y~_=A(RdWQWZ z2n_a&J{z^+e=6$T-1Bu=e}%FW-X55~ZL4yLXIPFrm$lHtDXz(3FN^YZh9=vyZth{Q zr;bsF?q1ky6&_X7-6&TMB`-x5 z4K|vg<86T~Gv2H_V@k2-$Hf zJNfZVH@~7nS)6!ApMV7bJdARd0y*Q$D@k8-=*G+{hHZBNWA*fSZ^$Md`w*eT#?UB6 zu`|N-JZy!kppbCJH+#zQ;Ehpm=P%FL-{$%zVvgR8H(|59guJne>THO68M{>EpvPiR zIVkP@?$o|-`nrzM|_BKe9HFI6Ff}wo|jm30xx6AW;#{v~E`&tL-?LnYmgY!;wr^41|=+z9xYr0##3?P{YmjK#QEuZ0X5>hJA1^MLfmhl8&?;0cl1~lGp*< zwSMp#k7NZgmllPWg0H(Pifwr+w{bD6-iL9?no~NoMz)O{G_U%OvU)#*@mnDFel!3( zBF29*y1k#_`|0>b-An-#Su`mGzqnsERsna7sbr%|ZdvJ!0TpLcAerRqN&r~FcGu@p zheaxoX8_8X27F(D0bJ`In@!y-qv+z(UyFx@>~jLL(+whfs5#=W*rZp-EDWwg@2~P) z(1dOXx;&nGk1=)cm$wp5?ypxH8Yb`|&UqT~MUelpfivQ;e{qi=S}tb>tJN&j$&LjX z0li_C`5DJjM$z68DSNzbuY=b@cf$TrI=r&7F<^JBx@+ZuCyMzhaz_B8z68 z1&PuQcVr!ldS190RoxS$!ET~%G1>0PNYXBaWDE(@*ERU2U~zRZ&8kPU0Yjk=rSJv} z#0}tyQhERkUA4Ck3_wVAYRZf96<<4{9vDT@dUuD7rCuyvkBkERE&bpA7BgT9(B1WH zn6XbR#}+);5;S)>cxlD@Y;8uF{x~U+s?`YPv-k~2F&;mO6j^dAODa&wm0rp zB*GhVjc=S8t=TWW_JC{{aOCfd<|We?EBbUEu$uxVrRfab05Zxa*L}ya*AxGEfzR8o z8?u{PGFGV5q3=3#r&!U0bMB&b+Po21@F!k^-wLd$5=A&O!O$B5NQpT+&q=StbDyaaq+Gn0DnT@7EnZj*E}C8hQRWlv;r#i9YNecH(7RbTc=C@B}rU*XANDcfcC&MKvV|W1{m5}|wRXtXf411pV zYhSWZc3=QdiB3_Nc1LxNNP4GmF%Wey_ycxaoNmy(JQGYqs)=GH5UW078^grYli5L|7+rv<^2d zAAQ=V5;O@bMj^i0ds_MJ7z3HV1XgK@hxE*JT zsS`lps7J2}WnXU3b2Sj6)%yl90HpWCC^+wr{q%bJmpZWe$m z$jZJ|yi{hH54@M#_}1Q2Cb|huBEsB+>UQo4pbpz<1~O#|lpzv?p{>H_S93`l-LJ9L z#*8l(TAtGT@y5~~0mO+pVHFTJSzwn)Y5EoZ!B^nUnE-t2xIJhJ|Alb|Y?KG^c~`V~ z`wNKAh^Mt!k6A)3+O?jdcF=I@db`kc-{G;j0qvn@JGUXD^{)zmU;6sjMEsbI|N23s z22^yU@SL|c{2$tg-k=ME-apAy{7v6Kl>W;%{}eziV`o0S_-k^1F4%u1@qhdP0Db{= z@Pftp??;MB0yvgT_;~+g1i!+zeP4>xbV~o*k<#V>QzUMw^*=^%&b1-B z3}kZYQst7)wTS=md~rZy;>&%)_*-Hx_{*TH;V!GM{B>Cn5iScbMNcRI-~F89`*WSd zLxBHea#Vife$M{{u_wS31rC+`msR^;)|vJ?z<*K?qXd5A5YE4_0at)20t$Nnep%k5 zOWLmI{RDsi8UA^O`~Ppze_i7LXSS%n(EFT7for(c%}w6OkNS7_(0To9*S;cI?i8p6 z{n-gbbZG0i!#{=mAFcte@&f(GRcMyLBmt_;|6eJL7nF}nfA<3TGqC@`#eiVmmPk`s zk)WNzU}k3iRupjzY(W2#D?rWhXhGOUeo2`M`5$pF_6`@Y1n6)A%>Lnj2?@YXdQ+mp z{6DV(^d0BWt$2UGM?l33)ve#fQ2%!n{Fnbp=%D2bo~r1d$NrZK|Doj9H{hKYG;nZ! z1t|ZIpZ}M~yhq0{hdz${$y%NJ=C6Q|7;S0!fj=zuTPF=PL15+|LPO4iI|gM8mny0kT_TP7{C8)I%FB@9^9T zg2X&95LGlE;MJL3uaes5?5#X9fy$llSLS%zE^%nG$>v3O+>Ht%?uoB~US8!t=Q4?< zp=(%~q~lL}G%n)n={Jd}S5c-HMF72vyf5N!8d#r97fk!81yQD#LNp*^W4ohFKiWF{ z50?F}3n+Gi7V^;c(CGG@<_Nf|>8RN&-H^dgkIKJ`iCuz<9_{6fFh$8zsPn!uyL;|N z41Qvv=+-FhR4Oh^IvB6Rg1pLBa%`r0bMglTux&u*mn~=yA(z@S+(V`!K(2igp#9&) zkN=A%`zaXxCCH2{>Lt$bjm|zXh;3SZVamnz_w&Pkfq;|#sm}U$W5)q#)>*)ha4Q2T zU)S39WT7jT>V)(zcwNMQHVWnZZ3&-)t>$j|3-Oz4ej&z8qbspPat>-HWk>nw?uB`w zmPxgbX6?qymQ!vi2uEu?kG>sFgi-5wSGIGgQ>9$-8vj8$rm&O?uTAx52Ewmt3QzrJh2@Web+!C-TpqSE!r>ibDr-b zALcLcL__WEe|_2?n~By1Yx}d^umw3rDSOE$x1^)@=_uQilVNrgUdO3sv*;!nH71*X zzvwg@qo!y}JiZsT$el88a9*O;edcg7R$`!M)mdYeh;gPqeF;Xe)WBpm#e>J;)GRd1u7p06s z0s|$89Rn_;7c9I;?+`)HL@90fm`vfjJ_lo9IenU* zaR+l1<6Vsv%!mR#3|ddjsq}KLJJ$O(3+z7k&0In82HfeL&Q%JU{dUdN{}S7-j6Tm{Y?^W_T|-y zN?ktN2{y{J8G1q2^@usIBl=8}%gpLrk}4`H8AdG_{I)UUG{5ioJ?`H#<&TT5?7yv* zr*PHZ?TP`r`ki7YyM#OQ-SqOykqu?ui`T|C4{pbuEfX9q!@S=6u?lakKPD~E%I%4YYMAW$ zR4sk-wM6pX3X84laYF8Ok<6-cMbsm(L$;)~UVewU9IyTHJ8>e$RXv`b;&qeYp^Wzx zV3>xEf!EWjHimF?-|zAxfxpK}0}00VyhqbdcUrnxRTBAw+D5Ql$4H9TEt=CPYQ) zMOs2AL1_U32{i#i;9KskyPW%-d(R)9(;RgF^r(EzBlw|Knjdq$%w zbN*$8_oGmN0l(UjTU6mgs(B|<`?!y-FEe%8x88U8xBB@OQpJ^%{&Xsr=g2%UX~_k< zelc0jKB&#Lr{`IpVky2J>2mbvHhZM;ZB0or)>Me_u2M)kuBX5!nr}+!-`@5w4Y=U3 zLv_!gllkBGq$S<0_99=~Y($LSV5Hr8A6QVRtQ({#qmvWISe0pMK zK6c$*?93i_iL_~^qE_!I)6l4k9-FEV*wJa76U=4Xu+Eu7)Yp_3+^Ww^F86dD__?Hb zPcWZ2=YHXJd@j)uU~2>4bRcex=qNF+8?!du!XmaVe~6BGa2wzt^8qcDu@&|jsW~6d zh#1_Ld}6TQ0#{1cpY1W{<$}pC9Q{Rc6 zj|1=+(S6(6b&y;9Jh_%PdFv+M5_fMn;i)X>zltLG<<8v%v|%$vQn?%*|Gc zg#2q|?bBZ`V1Ob^j3{Qu>Y7m^>wf)O|D_=i4 zEiN+K8U?xM(32*dryei)T(vR>jnqySsg0-;C@cCw5ZuRrXuLhseMN`c-FPxg;7lyg z4SMbPg$%)TxtiGS)Y`VXmDuTeVr#O`&hnH_KeeI@$ERylci-V=-J;*v$J!6J zU90f3E?&oM7+*fyK`Q+<2%6V@%RA7&!UT(XqU1y0fbB)ZC{<5%=XZhD? z=CS~d%I50=jr~VOwd3eKXE}z)UXQxPeZ;Nzer>Zj?;;PhDfa{9p?bHrCtluI*e+gZ z|AFK2_3mi?tu-R+U}hmZ9%{ipl+5_m2C?_eu+x5J&nYH>L$7!Ff ziji%b(Pc)3119`D-ME2NU}yu_pa)HwP0G;_w?aN)Na>-jP)N2x7|PQKJ(UA@8wqTa zd0O4+gK1M}j*Qy&?2RRT8fRYk!B`N#{*C6YQ?>toiS*q@u5&GREPomH5Y59u)r+YB zj(>k!plz*JQG}Q|ab4eMUY#fn<^wo%aYscPx)8QA9oEx*dO98Be&Y%Aa;B&L+8(^# z`!LbQOU|_jLWg4KFGlvC7VabmkTlEr)N{|)@WT;om^NJ;u&C~i-`PDorv;poKEhMn zQQ#Z7K&v2E0nRhBKX6Yg-tMD-yxmqWWa*2zq(Y(jIn}MT^PEzn2`LM0J=kR7(G#83 zex*HF*9tM_OIMz(KQ2aWg7bptxWjK=tL4eWJXczX8yyt^pbkiOs5!_rbR7xqx(l2EasA2blOvUlaxa z`g|OXK>yl>w8mrrG8M)(t`ooiFfBuHSfW;{j7IdOyScaPEAEY+SC2S9bn!B1X{=uV zOfdE34t3NCze(d4)I-%7AWWwDk;uoc z@@FFVyZ(%|LgtQK1bG@L?#!_RWTlXuUAh?_5cvU`TJ*F*c@5qaEI!BwUGrppN~aTv zDHXdwUzGU6sVW?wsC10#3iiqf+Md5;N+Vi(E`PfP+R82N&-ys;VEN?@#|FZ-_v>$6 z1ufxHl_D5KM3oyfdS?q4m@K(+y$+wN_;W|$^NcD zz^!^tMc~xF-)`l(S=}-3C>vFcCh$a%UKZU;g-Ml4tf$;XdT0Zr@hWG(B1t#z8cKEa zM7g$O=3P0tss|<^{7r9B2@s*w-<0XH0&7G z7wm9kg$GSRrfamUAG%C>Ih8@9?#N#?=#%#~L)M=eBMXPL=Gs5@7{V zP6%#P_1*K5H1Swv2Sky?F`NCJ4rK-DHl!NYivGItoj!p~HF$#XG~4AeFTBh|=WMrm z*CPdpZ#5?%oWF}w=hsZTe(=Oa@9P6T!J8`rYx(m}chTV&`s2Aemn2dnej9QRS2oiM zlmObJjoRL}9Cw1qJ+XONMf!)VG zC}IL6T31a{%6HQ%4&JgerXPCLEds82{u5;ShEzM_)H0i%+Ycdo4xYr7&5YH9X$19oT1#AB`=|xfK?5bNfX&4=sEU z32T6s+Xil=OxP1fk9MINe4N`M6c`_rZb`bDv*Da>M*g8YGS|u-b2GrR^BD`z{k@Po z7wx6)KY%%Or3nMoWnq9tVtjv4Q3$&_K58hl_Z9#w{ z#m}3-l>$p)xb)hN5Btzuoh8Yk+}y%}(Dy~oxJXaEw`(PLXA8)SM{GBe-duF7s zQjY5Fl`v8psp$BsIg@TDl2YeO1^2d)k<;pzd^r0G4I8x@4ZE%&6p@^{i&0 zpcI_r(BMNYfUSeR2hC}9Evv}=Qh(PTdsM1BfRrQ+sw}%6K&nzs?ubZi-_{DX`(~Io z^U*x=;CD+{@A&}V7?~t$d@Ed|RpSAlwN*is2di4sPH7=nI6X%<4^s`*CD%BlZGaE#mc)5aI&ezVu^d0!P=a3KFZYm+1 z=V-}PDM=_r$q0IG3q>hXx(ln2;9}pya4Ixm#d>2%<_Y^@VA(d05lGZ=7>%;*{INXPY-7jt`v>tl=b!nzI^EzNN)zr`C47ve)fndpd$m)Is zel5H&NnK6YHm=x2I~Ze&KQ-v&DkERR(Yaf7{3m#+P*qkHa>X~G1-?}|bnACT>zCLJ z6|~%Rx4`9(qc>JskLIZ&Z)Ln9neWGz(1lLc;gNej;pN>W#SKes`;5rFv8 zJW!t{me;s@O>@!Yo*8fW5eq#^>{wr8mA}>``b7gGZfC03H0U%+Vq{A&9yc(N9&te? z+1Og*=9jiC z4!=SU=m)R3aNr@+U7<}?hmwbAItt+%^j%^K52wgMBM?@W zP4P;sqsY(NDFZLMFHq723s}J-CFX-wy|_X31&cC&G)QZ($+Gj()gsAg{ z@RCSW_VbGYPi*lUujhtzvJb3YbSaztK7Iu8S&96tKkzBY@{%wPtKU8QIOvDqoz{t_1J1TxElqw93A9d5?7pBdb*MF6urb@y5SGR zyQ?)DM&+3%@SFuI-qE_P6l)$-<8n*RnUj!%INd3hV!mb-5fCj?T=aMrq8b8%E#>StC&-_Gm2%iar2- zHd|5~{%#+AaXv^#!ga)(1exTVejlpZ&S7lHBb(6p5up;87{6RBRFdLazQLHuYetqE zTMWr*l?}x|@EM4I)VoDL*K;J@8CMz~Ei(Z|^1+uH)aSoWMb_+oa28U~bQ+jevy|GH zO?7{lkCjSsowcrM_`WtL@V16fmV=ziCeoQW%3K#&3qS z*o`TusR^S?E{=4QJ^EVjInVER6Xl7rGgTM>#Rsu(V5$3AL0{EuhWwnKxED3x$YMS( zt;W~Q+-i+JE=|B3!C$i$i91qQ9_)Akj^PQ|m0_`l?4nX-I`RUtJPN%x-%-&3W?GE6 zTw25a?(Lfng6q9l_fYHL^dyys)nhOWbo%S9g8`w3p$Pcl##rO1GR3BK+k%q#V=1MUMv*GAl;5P?elMWR`xCq78Y*M<8um!^=~zLY(X~3~#qiIr@8eH9mG+{QZ2i4gi>X^4lh;72;S+YQMe+Mcc**(oj?@B;%;&*}H2c@R z!{jc?W_?yuW-OBIv(;*Htll7G1G~3evnRW6b>>UW6tHf~LVad%r)XVq8T36~$VJ9m z)H3!q5sSHnFl-t~+>NQx@;)N}*bcJY`TvTgfMhooKun zJQme+1l}Mw51cs2J6^jqi%LR5Q>0xlh4T2mUPR-_dTN!yQ}v`*+%Qdp)#94@qiq7m z<+Z&HjVgsLP$pD7gcW47w@(}R2<-Xk+sEg*Z>!bg@WJV4>)rG@9gsx%nd$d>?eGz# zM-CfkCaz7?)kkFel6O)!LrU5O)K$k3=FyvTX^L;bxhM8&r0*|Zkad#@v%8%dj$c*P z9NEJ=a&s^;aC}Iobbjy&5cPh*`uA_sh7mxUyk8oJ(FR1%66`gx4{{fZ87;Sk)NdDS z%!FgoFUCv48B?yc6I5g&@NHK+D6B~6$%0d|!vJ%;M6c}K9wmy4K!D+>(@^mhoR!2) zr|SMFrL8e<4JRZKvK%6x9b@eCn^xdpVCB3;aOQd_s0s$VvC!_AZtFfd14p7~_#B;9 zDTS@%x9V0yk=xXb9B#~nTF}tvDW!Z(ua?2vYHD}n157$cO4V{3@>Z=z_XqAmX6IF> zZAh#$nybaq&N0N9W>GdY%mK16PrMr&^}I$qU9QcmSCL5SF{ zgbZyv9ZPVp2oA_r>vkBJHq`nc)ebj95+}T(c2`$5bmV6nF0BBHiZ%`9zj)bB*Ox!n z=>hX&^{TXG`?2_N3GHuSMw@6ba>E{1cbSDlXLxK+Wlt> z5wxC)UMRh}GM(jAsEgY2y7s~rq}DS=*0I}Cz><1a05|>+edWE6rF9U-;#G!{+JSWG zzH`LSAG;ARYHyl?uOv8SFV-rRdcH~nH4c^v!L7d!9^~kedtblUaL4pPIzRG+Z1A(R z9T?0+QDf1|+Mgjg@6_$sUU8gyGUc<}LQUzd=5{gIo|Xs$=k1t>_rM_HTxndQ1CH?{ z&?6=BCZe(>c>^$7`lZ9r0;`?S>k~28;bC?36Y0DTEO@jZ_}jXm&hIV{oQCUGyFwH> z*f+noTBq%+Aq{9Wd@+4rWQ-(xehv8uOGmn!JJmEF;JUs+QdK;mg~mIxIXjYGj@~ej zy%&*7IT0OiJPwsyvH73~sfQyB-%umve0dgSY;=fEfP9iRDEU)X$U)UBH|yvNZ}E`D za=3o=6TL;8NF(HvKOt3C;9=C78{aASuOFT- z+M%nYer0t@2ml~J%VpsU#l=^kHM;qKW$d)X8%SUIFPh4tpl=j ztSK++aPcjr*vD;ss$6c2kKT^O>%qCmb1plkbzJZ3Yk&?HgmOIA-v;clC&1 z2D24=>f^nV4f5#}J49+^K|B2AOO~ebbuRu=bYR^;KE?avpF&H&F%4ONdpmDyD{@JX z%{gg$Xo`L;;#}g9Uxwt5Iu$QF^L?A{7mXh-7Hekpv%6lC2T8v$$T{#*Ob^p�Uph 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%0AjwwLcC7_cd(~SCo%BN7+#gJ-}1%F7f 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 literal 0 HcmV?d00001 diff --git a/docs/en/UI/Angular/images/user-prop-extension-date-of-birth-field-ng.png b/docs/en/UI/Angular/images/user-prop-extension-date-of-birth-field-ng.png new file mode 100644 index 0000000000000000000000000000000000000000..948c4a9fd542cff4dbcee0d2c53c9fd281e37435 GIT binary patch literal 154453 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%0A5bu;~@P*;Zc3>W>7C4mD5x~E_ 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%0A1#Q%InYZYaVoC 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 LdTP~AY~K6_NEhgy literal 0 HcmV?d00001 diff --git a/docs/en/UI/Angular/images/user-prop-extension-name-column-ng.png b/docs/en/UI/Angular/images/user-prop-extension-name-column-ng.png new file mode 100644 index 0000000000000000000000000000000000000000..82d72b40ecb0823e6dfcefbe82552ea8c311b211 GIT binary patch literal 82388 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 bV7_qCF+_-G;RSFyh^|~zzK|+s^zi=xvyF1L literal 0 HcmV?d00001 From a3f1dd1d191e8f57e8c36aaaad091164a477448a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 1 Jan 2021 13:52:44 +0300 Subject: [PATCH 57/83] Added page toolbar extensions document --- .../Customizing-Application-Modules-Guide.md | 7 + docs/en/UI/Angular/Page-Toolbar-Extensions.md | 420 ++++++++++++++++++ ...ser-page-toolbar-extension-click-me-ng.png | Bin 0 -> 106292 bytes ...e-toolbar-extension-custom-click-me-ng.png | Bin 0 -> 98093 bytes .../UI/AspNetCore/Page-Toolbar-Extensions.md | 163 +++++++ docs/en/images/page-toolbar-button.png | Bin 0 -> 45092 bytes .../images/page-toolbar-custom-component.png | Bin 0 -> 34814 bytes 7 files changed, 590 insertions(+) create mode 100644 docs/en/UI/Angular/Page-Toolbar-Extensions.md create mode 100644 docs/en/UI/Angular/images/user-page-toolbar-extension-click-me-ng.png create mode 100644 docs/en/UI/Angular/images/user-page-toolbar-extension-custom-click-me-ng.png create mode 100644 docs/en/UI/AspNetCore/Page-Toolbar-Extensions.md create mode 100644 docs/en/images/page-toolbar-button.png create mode 100644 docs/en/images/page-toolbar-custom-component.png diff --git a/docs/en/Customizing-Application-Modules-Guide.md b/docs/en/Customizing-Application-Modules-Guide.md index da18d04d40..3f8597bc71 100644 --- a/docs/en/Customizing-Application-Modules-Guide.md +++ b/docs/en/Customizing-Application-Modules-Guide.md @@ -84,6 +84,13 @@ Data table column extension system allows you to add a new column in the data ta * [Data Table Column Extensions for ASP.NET Core UI](UI/AspNetCore/Data-Table-Column-Extensions.md) * [Data Table Column Extensions for Angular](UI/Angular/Data-Table-Column-Extensions.md) +#### Page Toolbar (TODO) + +Page toolbar system allows you to add components to the toolbar of a page; + +* [Page Toolbar Extensions for ASP.NET Core UI](UI/AspNetCore/Page-Toolbar-Extensions.md) +* [Page Toolbar Extensions for Angular](UI/Angular/Page-Toolbar-Extensions.md) + #### Others * [Dynamic Form Extensions for Angular](UI/Angular/Dynamic-Form-Extensions.md) diff --git a/docs/en/UI/Angular/Page-Toolbar-Extensions.md b/docs/en/UI/Angular/Page-Toolbar-Extensions.md new file mode 100644 index 0000000000..187ac9387d --- /dev/null +++ b/docs/en/UI/Angular/Page-Toolbar-Extensions.md @@ -0,0 +1,420 @@ +# Page Toolbar Extensions for Angular UI + +## Introduction + +Page toolbar extension system allows you to add a new action to the toolbar of a page. A "Click Me" action was added to the user management page below: + +![Page Toolbar Extension Example: "Click Me!" Action](images/user-page-toolbar-extension-click-me-ng.png) + +You can take any action (open a modal, make an HTTP API call, redirect to another page... etc) by writing your custom code. You can also access to page data (the main record, usually an entity list) in your code. Additionally, you can pass in custom components instead of using the default button. + +## How to Add an Action to Page Toolbar + +In this example, we will add a "Click Me!" action and log `userName` of all users in the user management page of the [Identity Module](../../Modules/Identity.md) to the console. + +### Step 1. Create Toolbar Action Contributors + +The following code prepares a constant named `identityToolbarActionContributors`, ready to be imported and used in your root module: + +```js +// toolbar-action-contributors.ts + +import { ToolbarActionList, ToolbarAction } from '@abp/ng.theme.shared/extensions'; +import { IdentityToolbarActionContributors, IdentityUserDto } from '@volo/abp.ng.identity'; + +const logUserNames = new ToolbarAction({ + text: 'Click Me!', + action: data => { + // Replace log with your custom code + data.record.forEach(user => console.log(user.userName)); + }, + // See ToolbarActionOptions in API section for all options +}); + +export function logUserNamesContributor( + actionList: ToolbarActionList +) { + actionList.addHead(logUserNames); +} + +export const identityToolbarActionContributors: IdentityToolbarActionContributors = { + // enum indicates the page to add contributors to + [eIdentityComponents.Users]: [ + logUserNamesContributor, + // You can add more contributors here + ], +}; + +``` + +The list of actions, conveniently named as `actionList`, is a **doubly linked list**. That is why we have used the `addHead` method, which adds the given value to the beginning of the list. You may find [all available methods here](../Common/Utils/Linked-List.md). + +> **Important Note:** AoT compilation does not support function calls in decorator metadata. This is why we have defined `logUserNamesContributor` as an exported function declaration here. Please do not forget exporting your contributor callbacks and forget about lambda functions (a.k.a. arrow functions). Please refer to [AoT metadata errors](https://angular.io/guide/aot-metadata-errors#function-calls-not-supported) for details. + +### Step 2. Import and Use Toolbar Action Contributors + +Import `identityToolbarActionContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below: + +```js +import { identityToolbarActionContributors } from './toolbar-action-contributors'; + +const routes: Routes = [ + { + path: '', + component: DynamicLayoutComponent, + children: [ + { + path: 'identity', + loadChildren: () => + import('@volo/abp.ng.identity').then(m => + m.IdentityModule.forLazy({ + toolbarActionContributors: identityToolbarActionContributors, + }), + ), + }, + // other child routes + ], + // other routes + } +]; +``` + +That is it, `logUserNames` toolbar action will be added as the first action on the page toolbar in the users page (`UsersComponent`) of the `IdentityModule`. + +## How to Add a Custom Component to Page Toolbar + +In this example, we will add a custom "Click Me!" button and log `userName` of all users in the user management page of the [Identity Module](../../Modules/Identity.md) to the console. + +### Step 1. Create A Custom Component + +We need to have a component before we can pass it to the toolbar action contributors: + +```js +// click-me-button.component.ts + +import { Component, Inject } from '@angular/core'; +import { ActionData, EXTENSIONS_ACTION_DATA } from '@abp/ng.theme.shared/extensions'; +import { IdentityUserDto } from '@volo/abp.ng.identity'; + +@Component({ + selector: 'app-click-me-button', + template: ` + + `, +}) +export class ClickMeButtonComponent { + constructor( + @Inject(EXTENSIONS_ACTION_DATA) + private data: ActionData + ) {} + + handleClick() { + this.data.record.forEach(user => console.log(user.userName)); + } +} +``` + +Here, `EXTENSIONS_ACTION_DATA` token provides us the context from the page toolbar. Therefore, we are able to reach the page data via `record`, which is an array of users, i.e. `IdentityUserDto[]`. + +> We could also import `EXTENSIONS_ACTION_CALLBACK` from **@abp/ng.theme.shared/extensions** package, which is a higher order function that triggers the predefined `action` when called. It passes `ActionData` as the first parameter, so you do not have to pass it explicitly. In other words, `EXTENSIONS_ACTION_CALLBACK` can be called without any parameters and it will not fail. + +### Step 2. Create Toolbar Action Contributors + +The following code prepares a constant named `identityToolbarActionContributors`, ready to be imported and used in your root module. When `ToolbarComponent` is used instead of `ToolbarAction`, we can pass a component in: + +```js +// toolbar-action-contributors.ts + +import { ToolbarActionList, ToolbarComponent } from '@abp/ng.theme.shared/extensions'; +import { IdentityUserDto } from '@volo/abp.ng.identity'; +import { IdentityToolbarActionContributors } from '@volo/abp.ng.identity/config'; +import { ClickMeButtonComponent } from './click-me-button.component'; + +const logUserNames = new ToolbarComponent({ + component: ClickMeButtonComponent, + // See ToolbarActionOptions in API section for all options +}); + +export function logUserNamesContributor( + actionList: ToolbarActionList +) { + actionList.addHead(logUserNames); +} + +export const identityToolbarActionContributors: IdentityToolbarActionContributors = { + // enum indicates the page to add contributors to + [eIdentityComponents.Users]: [ + logUserNamesContributor, + // You can add more contributors here + ], +}; + +``` + +The list of actions, conveniently named as `actionList`, is a **doubly linked list**. That is why we have used the `addHead` method, which adds the given value to the beginning of the list. You may find [all available methods here](../Common/Utils/Linked-List.md). + +> **Important Note 1:** AoT compilation does not support function calls in decorator metadata. This is why we have defined `logUserNamesContributor` as an exported function declaration here. Please do not forget exporting your contributor callbacks and forget about lambda functions (a.k.a. arrow functions). Please refer to [AoT metadata errors](https://angular.io/guide/aot-metadata-errors#function-calls-not-supported) for details. + +> **Important Note 2:** Please use one of the following if Ivy is not enabled in your project. Otherwise, you will get an "Expression form not supported." error. + +```js +export const identityToolbarActionContributors: IdentityToolbarActionContributors = { + 'Identity.UsersComponent': [ logUserNamesContributor ], +}; + +/* OR */ + +const identityContributors: IdentityToolbarActionContributors = {}; +identityContributors[eIdentityComponents.Users] = [ logUserNamesContributor ]; +export const identityToolbarActionContributors = identityContributors; +``` + +### Step 3. Import and Use Toolbar Action Contributors + +Import `identityToolbarActionContributors` in your routing module and pass it to the static `forLazy` method of `IdentityModule` as seen below. If Ivy is not enabled in your project, do not forget putting `ClickMeButtonComponent` into `entryComponents`: + +```js +import { identityToolbarActionContributors } from './toolbar-action-contributors'; + +const routes: Routes = [ + { + path: '', + component: DynamicLayoutComponent, + children: [ + { + path: 'identity', + loadChildren: () => + import('@volo/abp.ng.identity').then(m => + m.IdentityModule.forLazy({ + toolbarActionContributors: identityToolbarActionContributors, + }), + ), + }, + // other child routes + ], + // other routes + } +]; +``` + +That is it, `logUserNames` toolbar action will be added as the first action on the page toolbar in the users page (`UsersComponent`) of the `IdentityModule` and it will be triggered by a custom button, i.e. `ClickMeButtonComponent`. Please note that **component projection is not limited to buttons** and you may use other UI components. + +![Page Toolbar Extension Example: Custom "Click Me!" Button](images/user-page-toolbar-extension-custom-click-me-ng.png) + +## How to Place a Custom Modal and Trigger It by Toolbar Actions + +Please check the same topic in [entity action extensions document](Entity-Action-Extensions.md) and replace entity action with a toolbar action. + +## API + +### ActionData\ + +`ActionData` is the shape of the parameter passed to all callbacks or predicates in a `ToolbarAction`. + +It has the following properties: + +- **record** is the page data, the main record on a page, usually an entity list (e.g. list of users). + + ```js + { + text: 'Click Me!', + action: data => { + data.record.forEach(user => { + console.lof(user.userName); + }); + }, + } + ``` + +- **getInjected** is the equivalent of [Injector.get](https://angular.io/api/core/Injector#get). You can use it to reach injected dependencies of `PageToolbarComponent`, including, but not limited to, its parent component. + + ```js + { + text: 'Click Me!', + action: data => { + const restService = data.getInjected(RestService); + + // Use restService public props and methods here + }, + visible: data => { + const usersComponent = data.getInjected(UsersComponent); + + // Use usersComponent public props and methods here + }, + } + ``` + +### ActionCallback\ + +`ActionCallback` is the type of the callback function that can be passed to a `ToolbarAction` as `action` parameter. An action callback gets a single parameter, the `ActionData`. The return type may be anything, including `void`. Here is a simplified representation: + +```js +type ActionCallback = (data?: ActionData) => R; +``` + +### ActionPredicate\ + +`ActionPredicate` is the type of the predicate function that can be passed to a `ToolbarAction` as `visible` parameter. An action predicate gets a single parameter, the `ActionData`. The return type must be `boolean`. Here is a simplified representation: + +```js +type ActionPredicate = (data?: ActionData) => boolean; +``` + +### ToolbarActionOptions\ + +`ToolbarActionOptions` is the type that defines required and optional properties you have to pass in order to create an toolbar action. + +Its type definition is as follows: + +```js +type ToolbarActionOptions = { + action: ActionCallback, + text: string, + icon?: string, + permission?: string, + visible?: ActionPredicate, +}; +``` + +As you see, passing `action` and `text` is enough to create an toolbar action. Here is what each property is good for: + +- **action** is a callback that is called when the toolbar action is clicked. (_required_) +- **text** is the button text which will be localized. (_required_) +- **icon** is the classes that define an icon to be placed before the text. (_default:_ `''`) +- **permission** is the permission context which will be used to decide if this toolbar action should be displayed to the user or not. (_default:_ `undefined`) +- **visible** is a predicate that will be used to decide if the page toolbar should have this action or not. (_default:_ `() => true`) + +You may find a full example below. + +### ToolbarAction\ + +`ToolbarAction` is the class that defines your toolbar actions. It takes an `ToolbarActionOptions` and sets the default values to the properties, creating an toolbar action that can be passed to an toolbar contributor. + +```js +const options: ToolbarActionOptions = { + action: data => { + const service = data.getInjected(MyCustomIdentityService); + const lockedUsers = data.record.filter(user => user.isLockedOut); + service.unlockAll(lockedUsers); + }, + text: 'MyProjectName::UnlockAll', + icon: 'fa fa-unlock', + permission: 'AbpIdentity.Users.Update', + visible: data => data.record.some(user => user.isLockedOut), +}; + +const action = new ToolbarAction(options); +``` + +It also has two static methods to create its instances: + +- **ToolbarAction.create\\(options: ToolbarActionOptions\\)** is used to create an instance of `ToolbarAction`. + ```js + const action = ToolbarAction.create(options); + ``` +- **ToolbarAction.createMany\\(options: ToolbarActionOptions\\[\]\)** is used to create multiple instances of `ToolbarAction` with given array of `ToolbarActionOptions`. + +### ToolbarComponentOptions\ + +`ToolbarComponentOptions` is the type that defines required and optional properties you have to pass in order to create an toolbar component. + +Its type definition is as follows: + +```js +type ToolbarComponentOptions = { + component: Type, + action?: ActionCallback, + permission?: string, + visible?: ActionPredicate, +}; +``` + +As you see, passing `action` and `text` is enough to create an toolbar action. Here is what each property is good for: + +- **component** is the constructor of the component to be projected. (_required_) +- **action** is a predefined callback that you can reach in your component via `EXTENSIONS_ACTION_CALLBACK` token and trigger. (_optional_) +- **permission** is the permission context which will be used to decide if this toolbar action should be displayed to the user or not. (_default:_ `undefined`) +- **visible** is a predicate that will be used to decide if the page toolbar should have this action or not. (_default:_ `() => true`) + +You may find a full example below. + +### ToolbarComponent\ + +`ToolbarComponent` is the class that defines toolbar actions which project a custom component. It takes an `ToolbarComponentOptions` and sets the default values to the properties, creating a toolbar action that can be passed to an toolbar contributor. + +```js +const options: ToolbarComponentOptions = { + component: UnlockAllButton, + action: data => { + const service = data.getInjected(MyCustomIdentityService); + const lockedUsers = data.record.filter(user => user.isLockedOut); + service.unlockAll(lockedUsers); + }, + permission: 'AbpIdentity.Users.Update', + visible: data => data.record.some(user => user.isLockedOut), +}; + +const action = new ToolbarComponent(options); +``` + +It also has two static methods to create its instances: + +- **ToolbarComponent.create\\(options: ToolbarComponentOptions\\)** is used to create an instance of `ToolbarComponent`. + ```js + const action = ToolbarComponent.create(options); + ``` +- **ToolbarComponent.createMany\\(options: ToolbarComponentOptions\\[\]\)** is used to create multiple instances of `ToolbarComponent` with given array of `ToolbarComponentOptions`. + ```js + const actions = ToolbarComponent.createMany(optionsArray); + ``` + +### ToolbarActionList\ + +`ToolbarActionList` is the list of actions passed to every action contributor callback as the first parameter named `actionList`. It is a **doubly linked list**. You may find [all available methods here](../Common/Utils/Linked-List.md). + +The items in the list will be displayed according to the linked list order, i.e. from head to tail. If you want to re-order them, all you have to do is something like this: + +```js +export function reorderUserContributors( + actionList: ToolbarActionList, +) { + // drop "New User" button + const newUserActionNode = actionList.dropByValue( + 'AbpIdentity::NewUser', + (action, text) => action['text'] === text, + ); + + // add it back to the head of the list + actionList.addHead(newUserActionNode.value); +} + +export const identityEntityActionContributors = { + [eIdentityComponents.Users]: [ + logUserNamesContributor, + reorderUserContributors, + ], +}; +``` + +### ToolbarActionContributorCallback\ + +`ToolbarActionContributorCallback` is the type that you can pass as toolbar action contributor callbacks to static `forLazy` methods of the modules. + +```js +// exportUsersContributor should have ToolbarActionContributorCallback type + +export function exportUsersContributor( + actionList: ToolbarActionList, +) { + // add exportUsers just before the last action + actionList.add(exportUsers).byIndex(-1); +} + +export const identityEntityActionContributors = { + [eIdentityComponents.Users]: [exportUsersContributor], +}; +``` + +## See Also + +- [Customizing Application Modules Guide](../../Customizing-Application-Modules-Guide.md) diff --git a/docs/en/UI/Angular/images/user-page-toolbar-extension-click-me-ng.png b/docs/en/UI/Angular/images/user-page-toolbar-extension-click-me-ng.png new file mode 100644 index 0000000000000000000000000000000000000000..fcd36e4a7b415e14768936e029d0eae313f8231a GIT binary patch literal 106292 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

#L)Y9yMur3 z@k@}~T3CN37W;W}ozJCXRnG9+x1v64F^+TW5>>MIG{`S+;seq81dZ|%;4+IAZGE#k ze@HjBdbSZHXg!m35MvyPI4PNujs_&&HGlC*2*r_*fevKBN|*3nQOs-9U?Bn!&CKvuSyHG_JLrmr1xaZqO}|92>QBF6ju8eA{NtJd5TX3^;}m@N^hx!FmkZ= z_j7&kXM1;T+M)`Sc=Oq5%*6Wa3UIU7Tnuq4-_%?tcC~1|pKjZ&iJSj0vsRq=Ey!6q z1*@~WpMF8p`OINhQ9%6^Q~*h_(Q?9-Z@I@mUCtDF3n80ui$UA7*ond-+X}+edWhAH zp&TZehij{95 zD>FoXX*woS4&#Z8jhY`UAB%4hoCQayc~#pJ!Jq9Q7IceTvKIV9{-Tsjf4f~ozXr|< zKOKVAA7yoA13p4+B%ZFJ@^&;Pbn|D+(Voj`shu0 zUCoHCDD4*ECRwpuq6aGWBS)A0=fx1h3XtRGsrtkk`+?}$EGUh2xB#O`lq}v4XZwEw~@`uqRN=Wi$b?kx;bh6S|{_zVmq7kgtmVkO;7w< zxmEAKF0Ameo%t+X$Tuze8Cg}y9DZnJ$nqbpznjl*m*>@EQjaoyWxr5|)t7V=_|eV_ z26l?sVu27#_Zb&91r@@xg=SfZ4$GnGUyofMvFnv^QuUPdsd1d&xa%{7!-;6A}1t-A^PGYg;yp##q{OCXFvU*v&``UgbUkxHb^ zb4O~9Eqpn&^80lLn@mBVFB&fV1aHrg>@P5E?a%agTTk{9uTtwRhk)f7Y6n|+We&}1 zDi)fK1>f@&I0{ zw;W%YRn@juUJ*V2r2kX@&<3!b!#mL@$}kL*X3ih0EZRC zq31L%sia=k=1bk5UYk!dpZ9gxkQaT#H@wdT(Az4?m(7}!KPoCK+f?`MN%CL#i>&Hm zaWGgCk3poM1g~15jN6>617|XwtPGscEW=1-q?#7sSqk^cbKBIhXd8pUK=H+tLpov5 zTVN&@1a770B|mj`}syM7tPM4{WHoprV03&JOtw(lUOZ@j5H5v#Tc=j>s&+`p|+ z8y7@gUuS~)f5L0!*c1D`7Zy}CSPHJKq>ByJuDqJLla1T!AJ!>!vw@qDAf31;(R1X? zR~o2;Pu^Zl+hH<*$>59=->q7VZXPtgXA1rGJkg?g^C|Y; zz5MAfl3hA0A5f%*9l{_4ZNp);C)5Q|d^O{OKi@nQ6|;#YWJvBNIU6WK_%|=Z(+w%v zMi z{dU!ZaT)YVH;n}tA7a=>j6`)Tc8W_I?Xg{9zuB_fy#6yTqG0?f(sKp6UBfwBRWPE`mLedXJYAams=~&-ZQs2{f-P(YdlPR#NpvfiM4A)fQ%n|!ZHfc z+nr+Qr7mYKcqX>;yA~FJZ(7KpSM4Ph6wrWz^}@jbfdVK+WIdhKSD}Y&dbPvkKK()| zvn;9q8*ymiWN*51;iqL8Let&h09tbiG$_1@t6tsle3U2~$F?Z5NXPlSu!tL`vU)o(tRst-*x*$(i1>2WZp~f71ivSCuMUix$aA%wKtvDN{D0ov&VelaR8n&LN@kvae zh;+}y7KIFOW?#o;;$Xi#|MlzYuoHj%_F)2_(@s|IDqI$%>0evZO)%|+-!}RPa3y9x z-sC?=xqH>QNWb>QXT~wZ<&Nl&0VqG3-W4QZGLcomA3q8{u#$-oSJ=4~ zhjIn`8J9KzHT`n!>Yow4WGRWu(2zwZ?@Fr6T`ht}{aY$u=^kcJg`oh%8SR)I^^$pr zA8m|Mp5Cf!t~(WA?hsZKOco>1!4EYDR8_3UZ0B=gs`7l!U^$D*sWVwPc0}`H$em9O z@77vDT4(ebxMukE#Vt*7p%j&G`TUOf^q5?D%(fik zB`^BM;vBlGt}WnBbko?$6{gQ@uGhGwYWsA!6db?I4m+@XX12&x@%dnIZ zgN6_TTKLxSd)d)1*m~}F7u1VO?;V%$VU4?C*YO0t!48u-f0|�|$NMDDOs0qkxK1 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�pO%uh5lA%)4<#H1tkxa>$f!(K3`~8 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 literal 0 HcmV?d00001 diff --git a/docs/en/UI/AspNetCore/Page-Toolbar-Extensions.md b/docs/en/UI/AspNetCore/Page-Toolbar-Extensions.md new file mode 100644 index 0000000000..db466bebdb --- /dev/null +++ b/docs/en/UI/AspNetCore/Page-Toolbar-Extensions.md @@ -0,0 +1,163 @@ +# Page Toolbar Extensions for ASP.NET Core UI + +Page toolbar system allows you to add components to the toolbar of any page. The page toolbar is the area right to the header of a page. A button ("Import users from excel") was added to the user management page below: + +![page-toolbar-button](../../images/page-toolbar-button.png) + +You can add any type of view component item to the page toolbar or modify existing items. + +## How to Set Up + +In this example, we will add an "Import users from excel" button and execute a JavaScript code for the user management page of the [Identity Module](../../Modules/Identity.md). + +### Add a New Button to the User Management Page + +Write the following code inside the `ConfigureServices` of your web module class: + +````csharp +Configure(options => +{ + options.Configure(toolbar => + { + toolbar.AddButton( + LocalizableString.Create("ImportFromExcel"), + icon: "file-import", + id: "ImportUsersFromExcel", + type: AbpButtonType.Secondary + ); + }); +}); +```` + +`AddButton` is a shortcut to simply add a button component. Note that you need to add the `ImportFromExcel` to your localization dictionary (json file) to localize the text. + +When you run the application, you will see the button added next to the current button list. There are some other parameters of the `AddButton` method (for example, use `order` to set the order of the button component relative to the other components). + +### Create a JavaScript File + +Now, we can go to the client side to handle click event of the new button. First, add a new JavaScript file to your solution. We added inside the `/Pages/Identity/Users` folder of the `.Web` project: + +![user-action-extension-on-solution](../../images/user-action-extension-on-solution.png) + +Here, the content of this JavaScript file: + +````js +$(function () { + $('#ImportUsersFromExcel').click(function (e) { + e.preventDefault(); + alert('TODO: import users from excel'); + }); +}); +```` + +In the `click` event, you can do anything you need to do. + +### Add the File to the User Management Page + +Then you need to add this JavaScript file to the user management page. You can take the power of the [Bundling & Minification system](Bundling-Minification.md). + +Write the following code inside the `ConfigureServices` of your module class: + +````csharp +Configure(options => +{ + options.ScriptBundles.Configure( + typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName, + bundleConfiguration => + { + bundleConfiguration.AddFiles( + "/Pages/Identity/Users/my-user-extensions.js" + ); + }); +}); +```` + +This configuration adds `my-user-extensions.js` to the user management page of the Identity Module. `typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName` is the name of the bundle in the user management page. This is a common convention used for all the ABP Commercial modules. + +## Advanced Use Cases + +While you typically want to add a button action to the page toolbar, it is possible to add any type of component. + +### Add View Component to a Page Toolbar + +First, create a new view component in your project: + +![page-toolbar-custom-component](../../images/page-toolbar-custom-component.png) + +For this example, we've created a `MyToolbarItem` view component under the `/Pages/Identity/Users/MyToolbarItem` folder. + +`MyToolbarItemViewComponent.cs` content: + +````csharp +public class MyToolbarItemViewComponent : AbpViewComponent +{ + public IViewComponentResult Invoke() + { + return View("~/Pages/Identity/Users/MyToolbarItem/Default.cshtml"); + } +} +```` + +`Default.cshtml` content: + +````xml + + + +```` + +* `.cshtml` file can contain any type of component(s). It is a typical view component. +* `MyToolbarItemViewComponent` can inject and use any service if you need. + +Then you can add the `MyToolbarItemViewComponent` to the user management page: + +````csharp +Configure(options => +{ + options.Configure( + toolbar => + { + toolbar.AddComponent(); + } + ); +}); +```` + +* If your component accepts arguments (in the `Invoke`/`InvokeAsync` method), you can pass them to the `AddComponent` method as an anonymous object. + +#### Permissions + +If your button/component should be available based on a [permission/policy](../../Authorization.md), you can pass the permission/policy name as the `requiredPolicyName` parameter to the `AddButton` and `AddComponent` methods. + +### Add a Page Toolbar Contributor + +If you perform advanced custom logic while adding an item to a page toolbar, you can create a class that implements the `IPageToolbarContributor` interface or inherits from the `PageToolbarContributor` class: + +````csharp +public class MyToolbarContributor : PageToolbarContributor +{ + public override Task ContributeAsync(PageToolbarContributionContext context) + { + context.Items.Insert(0, new PageToolbarItem(typeof(MyToolbarItemViewComponent))); + + return Task.CompletedTask; + } +} +```` + +* You can use `context.ServiceProvider` to resolve dependencies if you need. + +Then add your class to the `Contributors` list: + +````csharp +Configure(options => +{ + options.Configure( + toolbar => + { + toolbar.Contributors.Add(new MyToolbarContributor()); + } + ); +}); +```` + diff --git a/docs/en/images/page-toolbar-button.png b/docs/en/images/page-toolbar-button.png new file mode 100644 index 0000000000000000000000000000000000000000..05e3f9da112a4e4f52a732304c9421c772df3656 GIT binary patch literal 45092 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

+TEqn)vil;h$$vDlkh+ zO4Y^91(gM0fgdq6^eq=O+h$%*B_^L@i0rpK?fJ5_cns$6=bfoOm|EF25&msts4p4h z{qD4DUOa%!r{hj5c9sbD1@04T)tT(jC3+cyP(gM414mpZm}_pk#d7(V$;GXa(G7-Z z12Aa%c=aqxQ`U(PM)TrC=Qv9G{D=|B0gTGX#ymx)PVB%31~#l%rgm}l521y1(0}A| z?W1?CVVnm`h>K$%#RBp)qFBX&%oek+x@PVb-}$vt;V+)-Dyg3HU%hmNGYWB(MMgjO z1W{GrESjP>lTn+>ez3DTJ71?*MD!H7pzZ0-v5U3u!pZG-nVT27j`_&B4d#>6Lmz!;DA6AhHX}<90 zh|K8aE%BlOE}w5`G7%6w5q_D*&e+F!1j^L7KQHLBm zYGTrTy3jUuy*OcHr0W>X#Yn8eB@eE@b#!~b5tAW&)NlCbavQp&3QUL+Y9bS!swcrh zkYgPHVfKF>)R@bKG_ZD5Q~^<#y`H6qLhk#=V~EmX;agFImT*gbY2FEZ4#e+8R{|i< zQydr)nJZLhWxdO|Ft)XsyhH|VxL;q-RjYpmfDL6S$It}46RX!~rK$tP4yUfjgN#{M|6ASPe zybWdf=rj%%&LLhi)6T(Y_k!hhGpWvmgmKx&x>|IJ>^|W+v8wMNr-=|)gkis=kP43> zRa}!kA*t=CY2Y$BzJh9lbm4194`k*O{qV-4%cK-0i&iUukP>ku-f6*nunt5nG^^iIztk(O57*a5_OdLouV>19V7GM%#8`roEl zFDYDweAo0A&A4gLCrPRXCn!*&YaEQ9BIIqdx;Yg#H$&3-ihZ|bl8)@=%NloV7}HB3 zd7wah_X1_JWU$Aw|LL#wl7(7<*pbNQiquNEHw44kL6g`+`Ig#5vbgx0;y1msDI>LH z*IG7WU|=2QL;J-27vZGdou6zIexG}U-qj0JW=oSF<1l8T(hS|Sm{LX)Q(>SLW=aW@ z=}p{nB?ZW^X=9+hOL;UitG*LXIAac3$A}@7Pm3J^DJJpQ#AOzHKaTbcpyArP^N>To zInd_+1F<7|c)w*mf|rK2WLOiGajGyZ6&O5z4X zdh@#jhlY8og$z;rlfuh7RHQua^Rli+7Fh~2tv zXRrN1^PHP0bC=Vw+0EorPU%Y~y(63zhxUCJxl7fO14M>L;0#R?F4ogAhi4hS{5}^O zl_mB#;h%S74O#hwiFY5X`-Ugs{5Va2A1WVc%Vng!5v7nQpIuKQ+?vM6Pptb`ePgV{ zHU`*d6-FYxeyCUv2KH_Xab*IhipanveMH*dib4Vdz~uu`j0*U$kGvVEyo)XqPN1(X zTmR;BCKKOWFXPx@@+8hyYvTlK{369Rq8#9G?MNhvo{6TFzIBNwtG2Q3Ms43?D3#9m zNgQ?=E@kw?*4LWh1#roAki?1;=Jk7^lp{SUfRWMY)52ENIFbI0(COXMgFr=DRONmF zvx$y#NyTYX-{aHg5V?F7)RNMKUx%zWKVwA!v&Rq52lM;oDtHm)u-5=DDX|pCIfV6N;Zasb64@vgHa3tr=;#1m1NF^yr?#9j={&!oMgj3PMuNV zci>-5qHr7#uI{r<-xkQ!_&8DGv>AJ1a<<6e*C(bno!9*iynWHSKXg!ljLJ){J918s z%#R_YwlxO+0V3!Lq^ILO$x8P4ARSd87bS{cP_j_s7S&8#ZUr_U+!G7_mjy`F5Xa$N z2wrD>m43uhCf}-}1Mo;37R%tW|L%?w4?yGW8gUsB0bP!7$PJ9t=sU|DnP~}x-)0B< zgwCg=bbH#|(sNDEzNh)iexj78H4sgO6(~Fyg(Up*FI7tVUmWoNlY(c*m;by(rL>SH zG=I^FUxwx}Z6FM8me3aV;Q`p6nz`*ULti~RcK49cCHwOq4LzNZ1D08m-}@JLWvm)} zsWZOu7YH>&`xh~I`td)Qg&A5>LHuotInTuh#BRWtEz6%uJ^}`{@t3M0>A~&is~A## ze~KzT*L)T|LoAYqM1NcRLqWWN{0dr1SXjkt{YwpgwHYA30u6kRC@tiiYnMRme24z2 z{Z~W`$s7}V%l(*V)-|Rm_5?qbb@7oBfL#)@W$b9krvmX78l3Sh~pZm;<_St@O zW^}y${^LI_4XvBU#Er(4i8`hogkiz`CdGmk3I^IQTz|In`oj)$Ki_KMw^2y+uvzfTbLXi;FE~ z5rrZF%}}3s6hlu9!qCtdI~?ho>I`k=P1(1EWjx*nt+I`muLIf!=h=A@F3c#GHP?6s z-{o=jG5BSRU8yjw%~tq`hy0kVg$4-*6a%*B%sdih5u!l~{x(sOA^puaJv$G#2c0KD zrq>qlHW<}dvU6f zgw#Wxj!C*aIb6^^a@-VKrFs2Ri*B?S%;+C9-K+|*`WM@C&F06SJTz}Mq);PeEUg;d zDtNEyKk+182i_XyXgJvjFomghY-JH=NbS6d?Z`hA1?k7FI1lzjqI1rc8HWU)l&ao# zp90z)TJtyLta}GPt))n^rjL*}ih*++cZ-uOKa*g^6Yq23#Np^x0j$faX659jg{LG6EiXg%Z!(re)436FB>* z(CA3i@(Z{n7}W=sKplB+2#9LJhmsRO;!n5@+NSPUS`cBgTLQGS{;;A6+A?$@z^{O} z23HAVTrp8BxmSp{zl30S8`X*uWxHGRT-N5sI1;y$To3yVUmNleoo#{~qZi;lL(ndV zk^d$YjZ=lhNyqB_j4CyP{B|W?vX%Xq%9IamR8q+xc>~Eq$;{}tmS+{Ctr=LytOX;N z(^hVh9{JxaErorM*`-SOS!tsLc*0*ohNDADbwoo9V`^HSKjEFM&SET@si5nu zBYqR?&~7Qmc2-FK9wnv9d-Jqu@sn_A`;|a=v(>l zqCdS~VLgKSwE%Az-~e%I!Y^X3>msVVW}b6zV5>FzEC%&zXh80;=#M@+#UefFsWhaf z?Hvz5OljTft$tiHv(>cRd@D7So0^xFAmqLr2cE!VDP&$;o}6$iZ#MSWC5DW6W=YeY zdCyEwHT2WZUUX%UVWy66Z?6r!{k^5EI7QUl2GyF%6c+DB5t^Ed3&Vf%4>rC>dmk*( z6sAl)&*ZF~<2l;QriUyrjzwGB#N6QpWYDMKKTKTg}A>MlSBD;%&A;zs9y(5)1xo^f3KEZIrIV2Y=r4EMU zv7hNO)d#l+yE+EsmKWNaX&rR$D*Bh_y3k4{TbQuL-9NB`(fM%QHe)bn|stA)t;oG?p4 z+r$r_9=l+H4!+1Flz5Cvg%@?CK_WJ2jSDHNiIIzL7gn^jjQ$yZtu;Zi_+k_O$1jU zBfq4!CapJypk&RBTXsgJ4jXD@)Wtl7jotqBQyk};pyGqR6!>UiEc&T0JNFqP8j}~+ zavbD;54QzOpB9CEM(UbgR{E{B364N^$oMG(pX=YD6DP=l`-NqkKcRXMy(%f&x zTs$(4%w9r-R|h^|cG!3{8{P4S4CRK*9zoBp5sMFZC$3*-gPq|glK}^X9$s$WAJk_n zkHryHJ*jClh-r!*`_A>whgP;Wbo$LsVU8M81Me-S@`j>&4Hxa z)a~7)*UpO8d~hjwcJ7;0oI8m?dOTWk!va4n9a&i^aV=^t8vHY+(f;4`n5nXDQu8D%q+1 z4w;OL4sTvs z2ZxAil>!Q<` zr(eA`*3jgaq%Mmj*#wmUOtGSfiwhsuDS^smJxTiRT(nRX;HX&|VQS30JX$%Txkh1h5klUheJ7fP^-PzjRLNic73ZV%ba#6$6Wk2 zuHLwo?*ilR9aRdviz*OdOvu`st9mIjV2j2@%dlMqKFeElv6U za2P@yBQLP*acT-TVvmE4ZY7cP$7w{t9K+7#OZRs*z>C%8mOcg^)BDlz4&-OM&Yabo ztE(|NfLF?K;9-m8-6<{-07EIBaud`;;`#sRApB-XK(ls-wsLVr% z`)s04m5?LoA>P#}<<*x1)z+JC*vGWc>E?conh-0SR8g-;Fk&sl8Jj5R zCTmrXKY*2FKk%r!r6cyWem4UCZ6F zJe@v8f#)`3hia(3Z7uI?nfL<|)huXLtY|0c+?Q!4ai@AvtQ}y$X(MB&7knLZ6oDht zhtuKk_I}KHyw)Ve>I%sv-k%ZV+oD<+NvmXm!SACPi$#j}@3%bfg5$5a4 zo~72!lyNa-o-o8O<&rslL5w(isGze!O44D?!ZL4KrLky;f5^ky5|QBO2zNH?l=v5s1Fsaf#cH3?bVhf-l%F45dzC`HOP~_fWEvz(m%QpC=#q{3S-P}b(!{hYw__h-yIiWi%=w4cz zdPif5yo(anBuGrO2CYZ$HT)Pb{2aTbnbZ7 zqk3n59*Gs#H6seR+n$%XwWUTNFlN}5uKYDTZG$e5)pxgjT@Y1d32^t3DFNEY!Q*ml zSWMx249_zusl>=E+g%yc^1ZDyO3SJ#7MAP}-_NVlRnE`qD!snHizT3$zZ<#nfo`jnL{f-beiXIdG~Yx`Pw-;9a@ zAl~+tA+b}sAR${wmiT%Bh3jxz@ODfj1zss6110Y;=m{U8tRBqb7Vj2qj}m8?bd0~m zd65%>mRl*DA-|bs)x1?{WXn!G$)~Zne^6$J(28RwhKdGW_gpl9l)Ph2!RDh=ULeNs z50)|60C@sWZkSJjkXr(8ram(Y|C&?V?P20$oZ< z$*lf$-hnqs;@XZOMjJ|)Sa;?es_9vB0 zZby#(;1e8Ik#cV?EYxPtI8poah|&aP3R~bq?k+(T^fN*Z*8jMj#wFDi%Vlt*sp=m}9&kTsK%yR$f`q^%(5~*kNpS z{GSF+4@Lqk{M#vy$t&F~7kTrpYk8T{@?h(eLn39CE>?_`EBi>|R6FxX;&O`L>?Y=6 zDe7ufm^GpHtp^v)41)64F#pLTdnu_*1(CvY*meFf#qSZH;EW^+=R^z2tW<_3@2Y~$ zs)c^diJpf=vmx~c64tHi;~3|IS=}N`OcH}LwbH05i9rT>hI6`ZDkNr_l2>tI+4{w5 zT#?neT8OHg1TR7_8kdhhM^j*(JTW`L68Dm?QKd;Y8|XtVIxYea7Zn#ZZ)#}Z^(gt= z1bjioCVmN|$ry-MiXLXgbI*p@#5Vxoak_88A|7V_xo!p?xyv#|R{}JShd-0qnF*Vx zMkw=}^96X!{k{3MGoezIb9AhK*=wvu}zvOCvdskWk<68Em$;9HRInr5=;C-bgF2ll_`BNO zg~sG8R&$&7SsduljFM{nG3aE?V!h8OSi6yXdK9rC(w9S?405wiC_Ii$Gp#V9&XQ#`Nhjs zq#U~QNoWG9mPFyLKLa;&GSC-8uA@5yait^VVsV^9Hb`zoR_|9&pkXn=G212I{>%Ht;D>XP zxW`s05s$=6bFVwA1H^%mi#XWSH_OK+=hE7=QE^_acek>p)!s{u_S<$tHe2P3@QRM( zYHdDRV=5=HyXgMl)g-X_=0?$5-6QzXV#NZZ&*|=SU`Ier6;klwc5$N7T$@RwP*&gp zs#~4QtRJvjuSM|>8tJz;;34k56`u{br@dFb0@BVlkoiY|(cL|pl3?s8De)|g=*xg| z{e}$T#0Gess%L9tvEKYAo#H-#4WRq=(KfktTh4IGk5-*_$%17`!)vpGUtar%v8$%U z)e!`ERF!EDYsoX)&&q;*YE6!=91E{rBoiHBh!!sQZY!`$p$TqI++52-*rpg$pa5XR{#f-Tt|prTt_i# zjMBagI`8QMeedD`8Ipm_hMmUCplX+p{T2)m{hX4AkzzIvip1G3+rNVUS{JvhRlOOR zrQW+)IYu570vJmDq{U10YXyRwf;JV23bCxX+V49<#4o!`gFUV&LX;G1*%F#O`)Wh< zjq7hQS6c$@ggr@ok-KZ1@3u#!>JDHb_eEQOJL3@Sr_^MI|k{55aH|fTLk9n(+0t}t3Qq}@TU|i?);FCdKUOf%-!PuD@ z64*_e=`$Nm-zHmb=9PWUbeTGufhl{#-bxlIEmUOfe7O_N34vPp2^4&8VE+cM3 zn3!K{xM`bRiT;*jyc5OGQ9TK^+l!g0PdnxNCf1{^7FSS{k%YJXr|8-&=hefi0^WHd zM&eecHBKd@@l(lE&qc6ON8~6ZlkHTOVdM{?#hyv*DBT0A5?mC#U$bd;pf-0XX8?BD zJgl5^3|Yu+x7pk%iP-?w`fH4K zT=hNK%%b?QeC1#KfM_`2U9!vz@NL?LKo-TKVS4)CrgRWH?F!D_;)3);`GqZ}2QQzy zwg>O{0cU%E z4FCh7BAcB4n}y>6k36r{%$Dpj%t<&13k4I~ug`UJd6q8bW+fj=S%*Kb`tAX>!|( zCBr3)I*h17T4~$suE>>-xLLUS+N>AMT=9OdE$|uGaGEfaTDsocr7$&>2JUx;r-@Ru zpBLYD+@IU--=fF3+tO?qQt@s!fv|tav|aMJo{Njn05C)1p5aG@~akh?m9$ zGZp&L5yJBKnb?(^Tz8?zzxZz(QESmi(@sNg?e<#r-pbMk8Tv;5DT^79`>e_I9?|+@ zkN59c8udB4(+K9it1gQ>OvCW|o5k9DLAlg#%$;JAWl#OjpOQ5PZ~n(uSnt35J?n}{ z_1phUFK(py?4|9j~F>PMjc|E)hlh6G$uE$#WOV&3_! zd?jfkfsbw{whVJjlvjZd2N+Vf=Aw)?ntD8&Tj=AGGT53kvYLmLZFm4>@Lu-~5BK&W_WJ^fqv+xbNuE3R7Bj`eOVr7h+*5_DUY zKM_S!K_`jYuJ|^TE(-lsR1lW8UobpNl*XYiQi*V=o?%CpYCc} zz8S?Gw*T9bwjKH-TkD-+2Xwx#+YSd{i(!9N^FG$rFP0h4UUsD|&42w(*1>UGuz@0G zOmP21W8bs4;#)-(C&GI6?)c9ju;uweIFSN0H{R3qF+e}{)DP>=MsNK>C%*!!I^0_@ zgIfjzy0_0Ot;TpyQ-x3hG~z0wx3o>XFFyZ0XSImCs&xvR3;to(rmxeuOYc6lemgXo z@xHp}ZVkd)^2=R4c#X1%mK@$Sd~{Py++OaiJv6(d;TyP$JLsFYNb;Yqrm?;XCu17q zB>0=8cG+muL=teDd1Ljw@~S%IRb{yT-@pkclS+4cc1gSZ(#eO!35yl>$L@C3uTcMW z{%elog`Z39V5|0$%G?K5!v84Xe1CChrf~V5F>Fa^GhqFm`w3^=`rJ3D;J=67*O)RY z7=5^Sul3VBQXJ6yt2OT9e|>vv{Kl3WlD7cz{=WZ}=xQ1-aQn=L-+9gUVYO%fX*;#`+wXojayqfK?9R_9XfO$uz^6&htgiSg zq*N)G#(bsV(JeriFAKs#S(`V0(3a51A~@> zh9_BxCb2{6-nnt5(#w}=DQHi(QOiYI^N`iekGT7OMH!@g+5CbkVIZ%gxJ@kII;F}J z@wGzVGsU(cpdv%EB^EOsuL(e6p|7r`4Jr2dYEJr9m~>3bcvf3G#acK)Zte*FxkeLZ z#=895jn$bdUL8V4nMrbQ_QAP6S^QD0f(hlMgY(vTDJk5*L5~IGIwz?)aFc#QW`FhZI-^{n0JEDyzwvX2cvYdc|EcO!;b#+@Tv@uMfgADiy`0SJ$itak zx8)bKvakPh>%+^sHV;$zuL102uFd1LfPI_4T4QK#zuGM4@2QaA+)y6=dkgDYQzZ=h zp9E~Y#Q+$KlG;j%%<(A?+E`~1MOV{9>KOXEFE8KMLqD0`Uo&xy6v2JnUfE9A+fSmK%b482^X{MzfsSHG z6&(Atz4Al_hB^hPB;BK*CWq#Hb=)HI!S1KZ6|*f%RbgSuj4W%*ZIOWbATV%8VBhp)9zUm?nb ztpiQS9+((=tY1SkV?bq=UpiIsN_74hr|WR@v^n=Upr(o5=)k@)wOs3CtehU0OyEk`tt;H<=%(41MxmP+?pcbRR;xhkB zh+Qs11?24aETcH1CW9gNWl|lO(`>nq)A_wZ9}lZ-Lxw=5s#TiJ?JeUzwo8RCTB+xg zj}zmc#cfM9pQ4Z97dU2eF5Dj-g=aIiUuzqpUxo{J3~SwG3P6UWl?LP_=LT1g&5gkD zW|Csl5vNVJiRsDu>a0rRXs*XxaL5fVm88b5HS_B)d*wV6-l;ly!sA=azP`ger}GtQ zh)1%=)!x*<3a(F|#G zS-RM4(EtWkmZw=)d*hZq2``m%uuOu_b(hC0_g%%jXPv18KCpD4H!m!ocRV1lYV;24 z@@}>QLN@c4rVe`*r9UWQ4jx|2#dMv~6s9T{X{!^G89(RvVl}gMDdhVV-xyMak5#9c z6lhGFV5Zk;N4VvsVg7>gQ;DUbyoDDc(*-n3p*))xmElWIsYrHY60WZoq|=}zR!f?4 z$O)RRFU$*p+La9yd+u7-fx5P}is$TRZ|pW};4&RR7O0oPO4w75(ZfBV;ONmv=@Os! z&t9YWZ^d&@dl~pD>5}F;6id9b#1b$Cj(t+Cq*-)5;>GUh{(tH^%djY$_wRGxdJ_VI zQX(aiQj2to(%mhv2<+0GvMi{SNJ$F_2uLpMQp*BMNJ)cBcXxL#@T~fO_dA}qbIr^( z$J8~~oS*aj8i@7&*XR(&5quQCv5VF+Io}#k!EI%1f}+B_4*d`B`kH4k)la9peHHig zYCV(BZ8{K9OS1cU(T-e$B=$UD)M#l^n7Rz$B3Pe54v#EGU zRi)0AWbhH=v}h7Wp5s_tQpf`^(|S_J&V3Igj#(`dw#S}`zBEtDlUH55i?I>n0l>FD z@leF9eQ^}E!{sLFDJNkIDfD1ZjW-VN;&fxn$TYp$N)ZGwQa6rvRj@_3)fIz>A~21a z@2)hnPD~r)E4@a1yX*45>pcr~16Mvr8Ko6-ruDmHJx0g$6)>E6y6jYud=mn?B0XjF z0|Eq6jZE+6Gd0?Va*!C8MIz>yNoy@^rlbl_i^sP_4oKj|;Djf}i#;R0K78-IGnY(U zA(>oSVB%;?PnS5kDve1d4ArE(vA@ zHbt_9Z~_9hh>1^P0~VXBGopl~uZLU%Pq06q-lFQ-=q=dsSb^|s68_Epp&jRj+=eov=S?a=jWF=krQG* zB7DUzuHF2hJ;*@nJ=pu=qOrik3}7seJ3WlkwC^B%Ht1GI5M>)}5wWkXEIi}C{&~P< z7+GSzO~%LjT_AIXyu`i;H_c7rz57?)B%HXJXil8isbYUFc2PQ3O_Wf>+B?amGmKS1 z;^94MJ$XUJtXcD{C-f%qmn6 zA%bq@bd%SMKQQKDRO=eHLQXju=DM{i5u_ukTdmB}_GafhzB}ql)K*byfGY4KXTZoW z(fGwh2X?HKT7vb0v=*QHGz&l%)?Y9t7%(c223$c`%9XCtk)sw-)t0_30&BMt(3bs} zW=#m1O++Lp8&Y`qix;WMCnWw$x~`L7-@pLZ8<B&Lxs1l=(DVh@@wE474cYa#~%R+_K~#P$ASxQr*P;GC(u z({4W!c)1pbvD|eKNWE+V-h3+IBx~Ag&Oqqjm%f^DC3DkYI-e&fHp8~q+#YF3pWU%K z@4eEZTUNINFGojKLzvF{2ufs~^4BzVBDS_sV`-l`wX6M_z7$t2-?r z^QPU{MERqjkRLJC@m(*(x~g*?&lVvS zi2Y*zT|R{aA3zqxdq|z4@GF?b^xIGIA?dN>9}L3zNrM8QM`6s4N45_3d}7jBechfE zEO82YJ=s1i1$_hr=rH!8F0k2d~ql~{=@!F7Vc*0fx7tYuFTo&yU)?|R{joB8oj&>I|iD9ee!U# z?X!`(!E)SpOIJWbtW&tkR|Il#5m8=ir-)gO`=`r}$g9Sg*m_3J9`c__8j0F&m``M( zPX>c?;C{bD?h`g@0)PKCy{IAkv7v-JchsF7mGtt0nNyp4)>f$!20-^>HSasb^y}@! z=mu>4g9lPe0EI4z%X*0?n0}OJi$#>@jcf|QirUp^&?de!ai?4?FeRFw5d1o?ez%$y zCyI%puA;h^=@D%5deqcLdxS=z{5E9P@ESca-Com><6wLLw&{-d23yW=}5)_|OiyTN!kiZT*^R0)c0`W!?+|8Bk?DYJi0F*)Sga4^&qaMOWQ(#(7jSbwc;4tGv^ zpn=MGyKdJIO0K&RBqs1cYD(sFO~ad;7H*bjSK%^Oezr-e@sVnh50>7>f|0Xl9&W&1fJbj>ULv~G!ZHbDGd2M(adc` zBM=*Olgs;pm~D9&%?LT(ShEP+Olk7&v5r}E@XyvhUmL)tzapQ+i8syNw5S1?T%3zw zu$cvitA2}5CNGY=lww9qh?res=Mqz|(mCe729#Askmo#}+HE{rUU;lZSXA7tP8zVH z3tTLhbbS1}ff}bn?d|1NQleU34P6zCo$^b5SnCLx@B(fcau za*?L##_$%h=b&y&nJoAz$F2h9Gkf)BPn0^qv$~iUx5+?5KS6;PTx`DRDwW@+LzQ^C$lH~*mUq=9)}=dQ(iqpDXj{@ ztq1bmAb$Iei}t8>q4x-ko$3VUv&~W2$(rucg2aFlQv`=V7$p zXU$g%%a0$~DM*LW^Ds}?)F2Q5^Ks3IfBP~*YJZ82{&KItaj`sf>2%w)sijgLbr{>F zM^D*W8;sz`BwsYWhFvEH^H^6Q{z`9Mk7i0oq|`>79O};;T*uz6B*$EyQq*1kR37#1 z=%VhXB>#|P3>+XoKz_9^vY{=8O>DgHX)q7&pNdT*Vm4(@d!8XN^2V|d4hjQg&@nQW zo-jGu?b(c=@E^t`_*T(9>vLAT2l!l_>x(mI(sLJZ7>bZ@@5GcP`Oc2mSkmUevb!34 zq|HUfb{e-^{G!BtilyiIi*<8uH}fJ=KQ_z;=ScqOQ&bJHwG}oWdl;FJ`yf9%m&-_V z)%nJ{BW4nJY6MjW=|2oWRiPwENSNE4>{FH&cFQA@Ke3FAyl+;kTre)}vX9SeTXq_s z@Iyy)#5r!I=vB5h=S?Qq-Zz+f#@x10cJFxS$ehBHR0FP|l($h_jFT@F&lL4@n4DCR zU-il;f%R@HeLxnMx*u2tq2_$Uul#2X^FQQ9p~`cMM9!q$8!%s@upV9k)!imWnDGY@ znLBj>6FGdeT&8K*`|or43X*c$7WXfD=I^Kx;ntp}Sng5pm5j%7^+s1jc_pF=+lOd` z&fykT=9B{=^M~eLH)D@To&MdEF9OYpxCl=9Yj5?CO^cJ|UWo_D(TPSVNQ#xgq0m>& zH7c}qhrQO7%l-V?*XT=r)07NrhW$PK;ObB8v6ZYH44Z1%_6k132DP3+z+t;mgwM^? zx$#pu`gZ7mHEJsGY>8=RU+sDDn+_($mD&k=gMNHSzk*V-tEys-6Axn-(ks2!;M9?~ zKk>k?LDqo}zD36fUMzAbJ94C$+TO0p0dYY18l)Nnj3gfCn0nc(2#S7{(DPiFU<$}Z zSHl~TJ8g03jO2&(R8`g`>)T>)J$%3pR^NTi)=KaD>N!SsSUm~R4)ccG0pHOgV#fDO zniKp*7hmy^gI7Vo)Y&tGZOpOx<4s+d<-U>ULR8aFu=PovU&T-7s6GJs>u}39oDqO9SOx&ks-46BSv~F{nuU!>8Nb0K%c_kzn9k@+-~80(WS*K=Zax!&_kQ^j5*49Lpa6w+nAdmmWBh?~s3^|t{ zcm2=lfe+9B_g#~m zy*!>LoXu#jP27Q>^jV(x{T zlcinb@v_bl7|epBM!th7vj=MHFGHUo0QiM!xRKHYbV0j3 zIUO0g-EJQ+6otn?$x*E{2#hXuaymOFv1GULn^Pl;&7-Qzu+mL&fC&HAlZ5G zrk3I5T?hUbr&qTd3wgD(yYNi7k;Uc30MpHK6S|=GuC#)r0x7kvd1NI#kL5uo!{#2^ zOGm=Jcu1BoJ8=!c^wXO1uK5`50_1y0zF>}}S#6|;VeTsxc8ZYF(^`_?>_XEwUo)fq zV4D8W2@D3_uCJ&Du*ZkBy0Bl8R)*>*S|SQ``hN)46>n4|YpM-fnq8-M&R2Z={%yX| z;%U-i)CkPKjyAWekQ3u1qSkvMW9E>m{z(94Z8 zz!_AR|51cE9nz?i3`Dj@>CB7BK<@xPwOp=&1TyrKI*0Af7LlZOTvX2Z$>hO%!$sAY zh@whY5{h8V7NP`RF&*Vfi6<&;v{NoQ1*MyQg-Aj@%S$Y)Z+56Gt;d-5I`b)#8;9{H z*Ey`Ml$ZN8Ks}sBw_)CoTmvNY6XC9^91^W1^l|>zI6}rFQrEE1L7b{kO{s-ga7d6Q z>`I!qV`@ukMfWY3^t4qew*GWA=~a)aO5#IRv0w}s_l9xPQjzZTx3Yv7fjHx2x5UDV zlB6ypVm2SV59q<`ZZZp?8*~}tTiYuI>SIJH&?X2uA5FY8kpnq}g=|%M1^?Vna zaZ@VrxBz%HxUzd7O|pv)u#xmrsn=U-pUk8oorC=^U&0Iv8u3n6SW`W0SM%+wC#<~Ok84K_a-ZoM3V&Rzp3^45ztc*KH9#`< zbpKP6Dz94o#iU{hihgtFL#Ny6OYaQF3vMwDJ>7^zOW}v+RNL=;Y@eiSax5;yH8&=< zFgl*5^rSzixHOUEN**6$P7;D;g28r z%BQuf^j$gP29_eM1siZqSj?VX==vnb5Wp%nF0(C#0Y7*o>)H1mbigZz`!b6@X)JE^ zIT%!%gKW0LuI0?vEZ&}&l~r$i97-$54t11ppNn{RIkXpWls7h8=XHQRlDXME12WX^ zG!k%^D$0H=fX~FOL*6QHN*SsVz0o+0iTT+GY!b7zxARWktPyhXJb%ml*rJYFI`J55 zHMo6D7kR@q3q}U6W5|?s^HGSPmAT{IUb(Y5^w6*-A#?TU>s|OT?u@+G7D_T3>-hfVZ8Khm(*PL;rY5HN&3rL1NqVlxw535Jg{uCTE%|ZFj{* zCLI{v!~W|a;vli)fvlIteXYAJZH)W4Gar8Xfa>Cso?tPug+;sDBl8_VTvD7tRZ=Qb zHp`QK@3gL>e4;2dZ~Diw7ps^!@O(Lur$<+o()+C3hAYjb1{=ck+>As?=3(7_X> z`7<_RF*-@5O)UawEEwv}+-)}X(&NqYV*755y0XJ=^jMHIMN%|%x~R6vf&d#uSA$gD zzj&vBQN0nnAr>Qmc}AMK@t1VkdVhOMiCvsyPr|dbZI`Shrj0!INO6VYvuxJ*uy?7Hs%f2jjswQ^1R{ZpisUnGElmw=*;Pc7BQgV zc(qbyi@gr)D0S34C*@3K*S5TWQCPM~%QHD07@Gkie10)|*2Xc7Xgog!1ZC@WKXUR7 znD^b497%K3uN3E=N(*2y^{yOKA!JT;mGUat#FiX&KG)k=B{&&FUiMu&B5p5df1-Kl zNn=kN2Bibfhfoq~2a-g0u|ZgZ+XdIAeKMBj=dvHW?6BJfFAjb{&nS_)KTm%wHEjhP zC5>75CuhrN|9m}r)h1mac{llCv+l;(Czu4aUvBQxZ-gXliT3EN>$9Jk=)+L}$LsY4 z7H<*X&@mq<*x9hk@NPYR7_)rMQJj`>&`FPx1@uOWjcZ|w(I5L>GUkwn?KCVl5Q|9( zJQ&r=+Rl-1uaY^=9P(D!QFHfG0;!E)$1RNnmaE;m7h7^>^w!EBt8mp#$UO>fKq40$ z2G(nV0ApTuaVjnF@aCvbR{KlBg|`^{mGIR?;hnzP8?yA)zGn%MpGvzd{02czRHVX@ zaR;-+*(%{WPl~FX+$Gyme~psi3>{WglNpM9P%`ev?)Y2M@k{ui$kKcMjW;Y5EW1=;^)J`D0?eey9bv z1^OwvN)5kR5|3YFOVfpoar6@a>QD09sqG|3Yc6ua>Z(_5fcw+6A6wrfFJbaRmK`Ow zQ57NQo6-rn(nb{j01)}MG=lw#Yt31ecz7AIj;&P%C%a-BA-Nzt&5e^&8AvfhFq7dKr@QQr8_O-JvS!3nx<$ysq5{i;gMQ zLmfiz$OShH$&ZOA91WM2zMumr6s)pkBO4~#9$FnRy1*E|W{|X-zlhv%Q&RE`a^rbq zh0`E;rWu9I!pJ`@zr5T87H3Klm*$(4j$%jJps&U%bQP^ha>}B!i&YJ~3v=3QD#;4t zl;sT!g0uIZzTI4Dx*fW`AwG$`J=e;3e++2c&yu;_ne~;%YDXvRT#p>NY7#WwR=QSA z_zERPn{8}f^xPhyFvi;yOprynSg7S|4$DCyjbxAxB``XHb5#uGr@L zw&K>zZLi^(9Wttz+fog~yCavbbMm(xq$n-KY+vC6qaA7~A+T^MI%f z`NgGQpk|bbm_4kV1gyx;8Gf!@e-?~OEeb(rPxfl(Jj3kEawc2-_gVod3SCm95*LwX z^d2=Z6;CFQ*Jxi|rPkF=F8eUEa#H71D@vsi*Ft<0XROOs(!N0C$1wd$22FrRsWL=q zz((JcYt7-!%MIh{C?89o@@!T&qEz6h%{>^+Br-6fGU1@_flnhBZfl7F(OX%Nx2VTz zH(1R};~o!1Al0bowT$h`;U?Y4$~DMdMT;Am1rkVAXK&^2?bZUUh4m0{)a-@s5cqBk zCIBxl6?S4@+;V8}JuPTK+-|?Vy~Iw`;FQErFAfekTpUl6_BV>QE=S;*wHKjRd(wLI zB#hjLcYTeWXS%);`*+q^$=lmdEOdp|NNR&U@ym7UX-i0y#RFlX9iU)1HNAeDm759ithaDMc{!hTXQt;J_q$ z`lx2;v7O`X%Y7tGI1z4hD6hk2>_ms9dsMu}dzaqapEhqa1^-MhPK&0&u5 z)79|~qu`-V$Gm$Xipw;kdICk+YRZG4M!&1%PZazzgMTzi{4d^*MkBvh&{npigdDOT}t~<(9koG2%Vr4@dt>GhbNE2>x|}d`W2shL+@}! zwmrA*xMv#AEq~jyA5S_zd&%qU>pH_2Ob;Z%Q6z*PUJ~lyoc>T!2!HXeodG&)-(pwNSUDi(unLdj3BxSuiar-wvXT2^H zC%3q9+`N^XotV}K)}cJ}e}bz;6wRyEDlZ~VF$6ZMFbfHZrpOZ_82h;AW!@gngt$0?I`0t$E7O{CkoO$#e5jmYl z*uGOy9Ee^f<9tS03gjo15Ej2Ylp%jQ|tFz{1<}5h5r(0<9nlLsAZtj$srx} zyvpn+2s2%GQ0-@*G+D#@u)o+_VtJpyb=tP3i&MM_l%@7LH;tbg*E61sT$TKgzpzaA z51+_gn;D&g|M>Kjzt1)Y#Bic${z%En&?>Iq z7oVWuH{MS#B&jyFmBKUPFM=kn{_igVC*{OVk0=VF5eQd*Z$0jjnJP6kxt}b%`|k(C z-(k7l3B(r+L9flXAmC2+QUMsv_^9Qf8Sj2FgX=YW$fw^iv3~qh9=u*(>H*0Nr%av9 zCNKQM@+T(rt$s48^@Yx4IO&=I@~1P`-iN9SRF*=R38;QkneXo8?c>y&%x252^i^YFzR9Ob4(3F+~i-GyF?*Cgx$K1>aH|XCx8JXl?q?ytDy` zSN#^=#iO@*{d0@q?m911sCFaW|51O|7Z9*vGIKlC7)m(vAs;?0`%gSE?b&MY-S6fM z__|kc*+0?7zHK|3=m9HjG?{x`9YfLOQYC-c(i)W=o;I3<`nbveqtkFCqJ{6=b~&0L zuEFmwc1oc7`~WKYq$1_s{Xg)b*t=5|vssQ-u}6PfA@)Tzkbd)iH8I;C{X9Ik{nC() z8MXb+Ei~z$A(&^cSQ~oP5|fRS>czQ6up8K{&h7|GG(Y~^k<;~`>w5_QLV0-qi@3f= zHZwpqe|G`iRdbq6%%35_`!PFJ@$QdW9NzyQ@WdMj9D3EcGEBP*y#8JOowCiwTP!h2^Rq@ib!mjN#$^7G!wjK6wg|k zN(OEvAE2rjH1ip-5g_rDUf-&-z`Fg(=fVY(tA%gX!4VM~=}EJqq`S3cjUM8@!dmSN z;*7svVJYX>a=AH0jEm<1Y=?ULaKPBT=J*?}ca?uXefO_(^4L+xCa)=I)aLB#2&v%j zR6Om6Q<(w;0ssQqe-{{#o{0?r zM1Z)kfRbD0d6uac`ohxC)cEA1mE=`toDM7;F&tT52yQsP8KxX+Qn4DUJimN@2o#i( zoRY8yMFaY*=aqN;kMT+(bY5z`-NFEm<8>X4lE}&a{_{&ZBHky4`~VBy`Yl z4fwZ)k(--~9W6J@FCf4OEXQh)e7=(n$Ex@R1Q?iMOPJTx*FW9hR2&IbFJYmhpE|V> zR{&5@19FUsv)iYqT(+AX0+`7oMoCG^i7aw*h_c^Ek?_C304%r@ex~AIW4T2koVc>a z4!+zDdUSsK^+Og0YJlOOYqn?a=9}kv?cLFosJwpF^t_ z4d&B_OvxNvK#%?VW_g+vdBz0J^Pp2x<1iusu-^}(a|nO~L}6(?nSK0V{IpjpXN3Fn z{ApT}0^RoOf6kJA!2IcD0D6}(4^1e=%@X00CSd`9Qk7_%i7~1}w20!{ViaR>Yiwv9 zEDCw6Ru%i>R@emlQLPz}t2ly=JLi{D=l1>Q+mq?wAJwsgbOBX#{a5MN?X z!&lvRHnVTMrc5<#?9*| zLgz!+?6H);UrZcysg(ZrOCOG-iVe=01oyooWZ#aNYq_!~J8U&v4*bbESw2=!WyezJ zkwK-g=cd=V_eyW26+jt$cQiXu?$3qri;s^_ppZp{6v$=SR*&VvD4WZr3?Mqb&_?v< zk4H;%Rh+K>Ee6(`K^rI?jdzOs}}mUwoK{b0Ywc){&p@>AOBTLu?%X;-CGg?HG?0Vy*E~N=W#b>ce3bugr+4~U zf!988{$W&KP6opweO2YVBWAO8H|qVqait=>4D<}dsB}2gSoKH_@x9$>ig$H?tf*%= zKi~1fRI4Ih4yM+-ZvPpUuPpxl$iB1?SVccJO8b+m<@VWTG+*U!+8b427d@KDT~F*CEpa>W6VuuTtftp2J|#XslA3hPB7vSRWr2@IHGc1fh(F#67T{*M_KcH+C$>zgglk>%8tP37e= zD*#|KkmKp8NeJ<=EDm!bP~gk*DLzd%=n+YA5!4Wn54t^yLu@d9pA^+&LdAXzE#OgD zSy-exF-~7=cNebmN?Ve964ofUM|omd%v|HH-VPI3V0P2aoeA9Jy|y8ezLOca@i?h0 zpyV}MUH?(S>_cUN+fdZ~#eXk&1&aB-prcbe4NTvN|z?ZOlk|+7Pn4(B(=cM|2;a>j*1^=0mJ?U}-zn&#rMZ*klgOgn!cu9{iP# zS2!WTY)Z`rP`k}GlXqwSyi)Xc*n%jE%nBKIeY^|%$7lH#v zsQwm605Hb(K7s*f1ppJl5S|F69sq1so0UV2w$S2lsmi5%d!Nn)_O9m#lkG&~-^4B( z&MTs_T1hxW7LTL$U56M;vQ6os(uhupu8H_BhgR%>gsGHn*W}b!Ah-PI-SO0tCzw{j z5l!Ts%_wJ9v7K}@GQ%J4Xu{{Fp>f;Ge4Is*o2hR6@+-Mjk#RNDt0gVFo%hO3vQY=! zE))Bk48o@S%^BG5OFi!O#p*R+{HhL@`z!g-xDnjmC%C%IFGY%?!t!Gxt0b*hz8xy% z8C(u$F*NNL=FP126Ze&ErVp3Wetb>GW8hix)!I`>&h?i zqfYAY_p_O*oBy=wU%%H*>ad*mIwt_$Ll7zrKRQVM3As>I+`$hcw5L2wB$_A?-l*pRW98sW0?$y;vyW@%kg;HptE#&> z!P3%7I8yGFN}6;U`_!^QN?QDe#U7*KrXbeJ!o1W(Dg#1C$s=f!znFsp%&I8C{I*Z1 z+4-LS)N>Mm0Ys+KVQWu2nz}i(E(kF>>}#^PmpN7!)>B1kENGbpx1u6Z%tv~pKNqs{ zd=B2Ma{m0d`fAtq8@qAQUYd<-8<9yDxG~1mdcrDmEUD|v@$xAa5SEAai_hh&)WjQpTa@S zoWkk6I^O6w%8oz$(g}xRbclv0^r9_MIkHIMHCZ9N!yMsTN?brbC0U~k9VKq(?4Uob zCz0qHnaa-kHzOp#e$}mS?{121riAa|Fr+mvN|_9|?IKZp&x&uk=Efr{7}rec#MQ`L)*8mQW<) z-UHtc#2Uch!n2s@XU(;g(3d93y>*RCS6>z?ZK0Q$UjMDtm&ioCn!L5c*s6I%Wpdk! zsHR&@#j)hnQa9PU$1kXB%$P*x{Nx_De2U=qb;+#RjdCv6qJ8~TY-q9y_7jERN5M^@ z-?cyXZdMtFr`KhZ%1NlPx4)_PtlIk5N=~OsXk2}&oI%4Ia5SE6a<_}7yMZn$m6>u} zffNzm=z=i{Nb*>oLTe0XLJjE2}%XCYF{Kk@Q0$vg>rk=u+(XkPiDDAeriG|Fn z*;|#qpp*JO@1L8`lllMvNxv<(liC(4A=y1MV zOM`jlpF#u~A?k=Qs1xe#sf%Uu<1q^=YLB(OtX>i#Ij_f<3 zX-h-N{D3v6>7pnQNk~x-(^!tYe{giUdvZZZ#N2-xe)Fg-B)w8{!RtL}_wYa<@D^#; zWG;_z@NipHfgLW|ZA#|$JpA)EOOc=*B)nKludCI3GKR)kIPGkIOEacPm_@W7>eAuV zr4?;Iz9*{Y)Ao^7kmd{W%Z`Ul*}YL~KeRMt>=9xs7(kyf6X$3!wrIW9WWDt` zBdZNfqi5AHQ27_1x%Y*a{`}>qHdJKKHA6@#H5qLVARyO*Cw)wScFa#zrszoKU5!(k zoc+AJHmjo{b(^r)iPMchA+GacbEIi&3;M;ku0411Hp=hhksGezBPTqNZhIlx81TGV<~w^=R1G+swv%SkmWSER&E7SiX6(H=T*mRSj#tBR!`%*w6MCUh zkq$LZ2oJ6nm7|tsS8sGAp43&vD%2?R#0=vS+dNduNhDRYe{3%CVDx<8B3#e^Z3jLr zwM@$!dkV;?``W_vwg2=z8?dEwkygKP%O&Wf+Z(1nV>@4UmGOrwnant%ZJW4>3ekc1t=(c3q{sl z^(?FTbO^lt`_I;)e^CBTRT_SK{hxKh&77!hXQTI8(?!l_qD_C$PVLTzqlpvOW@i0e zXN=^4Ms%kydhy78l-U!@G90u#Mp_-hmGhYJ+L`jKsW|wod;N36CIWulsjHCuk zdSpMs5-672o(S^bDqxG&?RL?`w4%z4@8iowsyO3YX5I9=84bSf;(R$U53Izhni!Ez znvB3FB-B~Jw;5CVm+CUN>Fcv4o=|(V`*J@s_E$7GDE&BN`a_~O*McfPc&`|bJ6icIT=QcM)`qZ1rL!zG_?g3s;|0=tn-(%#44awa-$Nly8J zNAd7mJ%-fo6|v8Uv7AYC2vN)|6z;`^nZD?v#(Q_~I~CnA%?IOU&P}TISnu5uw92-9vR^Co^iv2;gBx#$A9mSF57!nW`3%WW##MeGn=n1W~Uf=7d5*d8k zOV#@u24p9)j5e!bh#G1yT#ZWGWpjAFt70*e88*fw>>iG%N=uP8gGWdVXt152m$;|1 zLTkOg{(NK2t8NJx`(+N{v}iG^csg*C7grzzw+buye!W1=iwf2(Q%0B5$wXr3V>aLN z#km2gxZ9rg*X$=v?xDLbIFEsD?i^aHqs;jF(@GN z=QTwB<>-sq6tYf+D&O7vD*i+z8@PF*dHQci%$U2x9 za7V&$lTp7Xg_(jw+rSPhWGR{X%Q~zBsn_IkwbSU0HKJzqg#Zv+x4S8!kIAYIW|=7L zXA}@Lb;bLGhWtJg0{1b?kJ7(Ve?+I<=J`|bdmN$@hIlNgj3I6T)-#J ztfKzw!J;~97xCP=*F;qOJ02N)ma}_7By59y1~+Z(`ieHTZ!?!56Kr@_#Ft*N4} z>jIALkFo|3(yRAAv9Ox$P2RotJFI6VA&N&TE?(V;C2oA}Tvhw|Ku&G=E`cH}>|Y)} zuiflj1i3jv4Bh5~Wly3h8%>0do#T%MTmS*!UzURASDk1?-ux&QH|$pf|3Y^nk92L0 zfrQk`IzeohpR8F^lRaw*wULe5onuYYqA<&~ux2`o9!*A9*_OOye-;U90=r~=B^H2t ziFB?558$o~4L9m508mJg!u6o5-_3Y%22LH-;`re?53a2yj_BpX`t8>{+ZKu^`q|U8 zxT&W+6p;ST$EU^vll~#v^8FiSA~XPiFg*&|ZivNcE=uujQrIdTjoJU$w~ArQ-ZI`a zl{H86eUUh(MO4?DYNt1O!GzJeOL42<6}3w8O_)~8fA1{{&p`MNOLSnB+|x4o)`dsHRLgk zpwUpCVMQF8GdMzaBiip=Cu-5oV6-&nF9ewdd4%2<2jd|lI;eDugXhdkYgbmImt~pv z5;x(g_A+`@Z!a1VsMD9XcR!%I#CK}PbbN+3iv$J1YqZzZ-nO1us^vL{)?R)uZ6eZ~ z)gXj97|pFI(4)IN`7R-aT%SSnONhr$8(zHcQ)|Dy$+TTKorP*<*<^YHi9?lpOSqGkfGun!qcDjh8Kz8w`vPz}bTaM*O`S*|~B;E3LnX(Ak7MWXN zL~zBakx9KEx?6cx5$sSOyd_fYs-;@l5EGnd7)-D2d^-~l()h$foAXuOA%t_3Qi z^mWOW8B)GC))~1-Np6l^Dr96=cJ`$%Lh`$qoX69#l=OSQu?+gn4vKS$E$72?X#&66 z_J7v{QUKBYs9`(%)eC2lPCl%pTITWPq1V`p3Ab(r zPW%mdu7qUU$8AS5gD43LTAmAJea)&XyEEmD_E%-nnWCtzPiN0Qrv;6BCuRrffInUK zEcNbwD@ux*Cn`(hH|s>Et9tay;F}Prw)8;j=2I8(K4xNnVCG+ zh0dZW8hQuJ-0ml{`=or_cWVgE+MP;OV1g9w$=TKIWAf%onS9>LNc?6VQ<>dFb6st>sUtP4yFYVy-5OabCqZY9uxRdY4 zViR*PZPU+!Lo$jfoV_ZA1V|mnL$7R1HPjpCzuLcCx5~<2$F5`^k6)8i5>niYs?Zw0 zF|yltRJ0v;?K&f;KhE;DKdFq&gxSv}fQCWlDyc-(w71FaY|)6LP*x?tUwTeeW+rG( z6S)|dBaaNM&fYSmMGxdRFQl+HIs3^tTzAUa&i^I|9HjVfi2U(L`d}vti_zEqJz~x8_fFr{v!c}4s8FW`WP(*559VuSFizx;yv=h(9rPh z6^SxDp49z%JFi^}4* p6v(&8;BcoqkDH?LZWujX7lq6N^u_$@lGrz%_-Y-mW&~R zrRSqBUF{9rpG!znSARaesls;7vG%RE_Kp=Ba=0MzoE7&lN!1KSJ+ z^RO^JvWnsY(j`%%f4VcoR#ddr76Q~gqv7lpT$f5P7wLVEj_ctjQy#kqj-g{7eq9(GDU`7mP6)FaLpQrE^_Lu$_KGKeVB>q?;(e%)P4=3VeSFq9LhPDqttZ z{I}-P&20|(c%m5No3I28U{Bdg71HOOQV!Exc!uGCXVeh+GLx@rrE6^DHM<}q*)>l) zvnoAJLwFG^5HuPmU3^2eXOps4HrJ29$3aCuC(38XIGT4V%L32$vf`*zc2BBw0Ip$w zJJ%b5`&E_GRsQiGJcNM^O(VGt$dA{VH*oqxxU}rf+MX%Q@F{Otd7M5PzwUywvyI2{ zcScJgL2;H8255WAl;rCWblR`bZD^B&1N6ARGxhkdZK%m>Ppz9+h`jI{_lQTY{5|Fd|?zd%R<|D^_lN z)>|u#8}O@TrzqgJ>9=J?(8)+y`GYnP1;_8S@nY`H3eGjfL`o^wQ{1R(lH6QIlL-;n zVU0MOT=s>hXG(c#LrqKTip?T`U`r&6AH3jjcIKZfok=@rHkZ)Aef->r6@`P zu=|32VLb)~BvhPe=paRn;Gi;%!Yd}BV>wet`7vpE3GrOKz?P0nkDNjQdaojp4(JRA z1grx^(%xIh;G$c0grewR(~m|6DO8Oj)z`Ijf*O`W1Y@fMvysHsR3p_mc9}mrur5|y6~UR>D?0DEa&cz2M}q#6X1gwB9YMuNHJO5o;314r!!GkjiVush?oGdw#faH ziN@~awtK6|;wi1$QvR5QmCfcn(;ZHrDeX;H{cdF;?+^KakkRoSD^V6wF~XY% zvrMd@r9!!I(M7Hz32D{LAJ%lwc6nbi-9Y8*!W7+X+1lk&mDfF%N{Oq#-hB#zjCw_A-x$ky@%D33rH#PlcFp7pTa*% zu&K;2F)@9$ENX~8s@q0jaXG(Ri=uDn%|nQ9x;$3pbVG{&A&p|6tMYnS=ptX~)8_fL zE39cPuH)lVAp9~^1OpB>`$u^(5i^ssR@QQL2iaenB?h9FZ&;O5g$pD^JU=#4GEI0VT10shY{`p@u@L+qKB(fNXe z9kQ~#+|t%IdvZTHIXO5eQmG;tPYQ^Wm6YT@n_{nyj1dC@vDeo%&(CiD{CXxPhi7M& z`uYO#L5+<_;rY!h0RaKKJ51*uNRyK?hJ*e4hliLL7&uYnd2+F!k(z48f{O|{F)}ha zG2v-<%Yo7=6LotQF}!%sc4Uwpn(+XX{q|3)Fdgr>}D)U?Zslq!lV@IL?h|%lwvy-c9N>b99(`%RBX=EhGvHIet zrl$7%{JglZ;Oy*-?8Q3@i~TknKzcPRRDvh|wTIkgceu@02^S^h4-Ru@<6Cz-OH0Q0 zr{YdQ9JVoCtt(<`jx=p#L>o7LIeGH~-8ks@4tFzATE=0hMv(2s5LxIybreI$=hF|n zMXg%(Xss<2UszI7(%kIo?(S}8HXMal>f+*(ot+IItiab}AlfE+zx#l&!ROHFL zv9j`cZVI#odd7B}-ffwyl%$&9M88@SeyS0}0K?y$UNbyT%IFCmEq#B4{OJ3Id+g+4 zWfj@j_%INWVqtmav(_2lf`I-@nq1M^+S<$vHex_RQnH&G0wa(jy_uzS|G90qy{;OZ zfdf3}x1@@Qruc&sb;#}<{gW!Y(@yk`W{$R6X3pUehTtCT$fIS>1@}@Z>+{sseW9mg z_&Dc!uM}lr)=D>f(VrQ}o~9eM7OP+^!Xe0pvz!abQuFzp9+oGy8Z-YAS_C^O1(!B{ zv>GFa)Qld_In1YWQN9kXs=A2GyY+h@%b&E-TD0pmPphn$aT!c8g%;1an(3=HbmCNt zXFRNcT;u?%Ln~2t!I3@&(@QC*p&6+_!HDbyXYAa}8P`E6R)P7^s{0rTCk`#!dbn-V zw=OuK=W(shd1t_zuy$8BI`-W6DaD~D^~EU9NeYr zZSn?z9dG>amKIYPB}GZ-MV;3UKDYEim9}o?SVd;rD~9SX858LkN2l36X2GhfPqWWB zX4(orQ_QFz?e2{kC(p-s)f~-)8#gDt;|`Cn6A|gROlwFg)NEGwOB-H}OG`hNn2NZB z+*L%7hc=+-mv09}53;!QujijsW&a&SGmZVj&*w5k( zoO0v8`Hb56y5yHn8KUpexzl94Y9uGO{Wmyu=#|_G>p2 z*Qi;>@$jK(OK7!&iw+|JwbR-;Bn3cA(|(tqlU*;enHj)Vo|QbBaypR?sylJeD3|5e z6@-aR()p=6YxO;n%pAv|xG|w~dV!m2QS|P^6$ckW>}=|2_=4iO%`*xY>!|SKaBa?m zMCNN*TiYUcXF+CAe`ywbjIru47!mgcBrU_wRC8wE-k>@JQ;Q<z|ep7 z??zWuRc&wUq5mTLD(>OY)~jdd;&OQ7X3>~V6t=biHsq5pXfZQsoNc- zRD9I744X?}mmptx$|v&`lITOQ^gQWtBKDE2Qy4{<)ULU~#q<4v{k3bIpu&vS1W_^? zA>aBccFUG&;qOZC-#O1k$;TN;z{F%y)Exh(>~N2yN88(=B&qmce$_pyn-TAJkjAEV zJ>TZ4>#;kM@`Y_Zct zXZtnlkc+H}kwLZ->$xs1QEt3YR2fV5c04dS=%M5Si~B6Egzi{J$Bhpxj<}Xd3Yrr%IRb++Kj7r{eszRHv7kTA;)^f zVa-H5Y^$Fi&BEQ68oE+OGy87r5kl1#Z-+yM0X(!<7!U(618@9j`PwohyVn|-x3{BV z|Dk5dY$@4&d|Y&|Uy9zqbzdNRKMf?Fr;XU>K{AxvB(B#AD5;i2Zcp1zO<2vIJkXLY zZTa2}apRSr20BZ+9}-(`c^j|Y?Y~y?$&-YCs)vmE1(1#$9vHZ{#J zExEe7E-fq+m6WivvTAqxbb|1!s_JsKDB|P<=gFj({ZAp^xA$IZ`-KX%DNTB?xxa&% zU{NIs?Sq5C*XjVQ$tCmR#C+`9s*5YqH!({`o$^sKuD|io;J`I)C8tzjQ?anWyL6ay zK^|dT_RU{BC<#Jh=FHeN&FH zzDt$MV*?PB2{xa!4GkBwh3G6Xt(_vvn76I0HAhwXjM*?u%ny0nAED|IhQ1hOExXR^ z?+vEtR9Go9k8{j+An0aIjJ=*@#Ii5hY#MFmGWg3G&Es8mV9b;n*?4@={`%#wH0AWr z!0|X)QpD@<@sQJfqy2W=rYg$rq%Q@%sc=0K<9dbYcZNGRiZmt~Hg{)nb=#7d`Mhhn ziEw4@U79OzO+xhK-PKM0a13VKeqgDKr%a#6cpTJXG=-$3lrFeu9PUC z0P_=JH)MX$NJ51Ha_h&j!vrc>^=RnuSgBY+f*#~vdM%~>VR551QxO6yf27sWET!n`#g_!AMEjkz>R3h;#kxJ%tGby%|FI0_>&ExV;$v6mo z%2d`{V9=qUq|9j-FET^%bR-hMkDWw?BohmZwCB+34gH|exah~ctn~#A0$Bf}XzrvW z_WH^631)r`8u#~Nl9HxlhY^n4z2H3 z8Eu4=;Y?{#(18Lab0a>ltE;QCvIu}}j_ia4PutT5UmVP>wF&t}mARr8Pw%0eKtt4RiaflvR{1g_$3fJznzCuZEZ_1)SA6N7HQ~G<|I|rupSMHZ$i{1*VU%nmdhTBUycel+YZWm_}Oz!Ra`o3c#Mey#H@t;C4Fd#|7`FNU`knpM` z$H(Gg)fqSHuzH0Gv=5x0L;8WLo1DD3xX2bj^z7v$BU6=>l$4W`leXfWf{@VsijMnh zgrd6h{X98_ownTF=Sdw6%#U#biYGE8^&YoXD+)r->RXP#r5#sJA3&tU)H=Al6>54T z?8OG{NA2O^%mK#I<~KEGxq#37E#y0B%~YN1{taT{I0UB)_sbsZ@D5^*g<|ehajb>{ zq|AO8<$|Jb?$v_GPN*@Z3d2YoK!C%GAYB5q-swf+1MO^os)-;N9uyH$de!D<;;H<* zEA}YAIdmW@KK}msxfe(`>aIWl><&hgy8Hu2jCSu{qNAfh$-Q!mGaD}5#G%A73Q$vc z|M>Xt=BZ4?h_*WgOtNhaW z0>h5tlX+UVjLJ)QtOQ7+1l#m<#aLFKP5YJ((2)Hy}ax{XD54P zm)Jg?5O%f4o7Y^cx7ejomsBc}z@vxfco=@_+L*$J!!Q`l`sE+D*c;}!860$ZztL&6 zJe$&+GNpa_@&yqZ0!YuuV8vw>2M-_uwRbT*x5E#XKNcI3gXh$`wT`)*UO8l@5uy9^ ziYXd+rI~yp@xt{CldbTDwr&?MZ(XF96OY&{bllt@=m3Uhrm=T(QyD|7IWDie=p(ct zBVR>5txliL^L;!|MGL=!&X+!{!6mHEbx0Om`1o}C?$#=z)H3#`pKSCjpL=*D#ntI# zWh)IImcP^QQ)BUO*S&zAigi`nWg^~xubb43J-60XaSL;z#cob2@+q$B}#{Vg{A4F5Khy)S6zt>Y z_(_*v%g|Y?4FMn_t-z1v>iq=xWu5hl3PXWumt;(q6F~?sUi`rCJjzG(3%GU+f6DLD ze~am|ql2yIQjfHkGVJ}JnuRxKoHzVHx1knz(| zS6jCJc4AT__vmo(Q4)Dm5+|ZweLK~}3^hQ6Q>PPHUVe7DK?o|tWA)1vh&;+so=0>W z)UV{_5&Qf5tE;cT2J9c1ymB|SyM>%RM|^yA;juF*dihV|K$BVEea)c)2BhM(~2 zh}UVt3xpt|Tvb#r69xnBJuWIYLv_lTi77{oH0<1>WxH-fwurJtQk24q09f&OkIqM# zJ48$o38k`jrSOrO{cHT3^}1hkws{5lLL%QO#lL!NXk(67j@Rn6!V~_P;J}x3?)Q+4@WhB(3DpshrlzRky3O3)-_+j9q{ors1_6;e2r&{R4nVuC`_A9sZu~&u z_`+VjYqtZbPpFC*p$*7SLJplHAx3Zx%oqHV8`<``EZ?(}gRa@U8+%|%+uxe#<) zphWRs+Gj6Z;7bqtUR^38FpcNI(pD8{YyG2Dn;BmarjE$`bQ=2Bodxnz878W@q`BQ? zOH;ia;gbT0V4w$OIU4@voca)-(@^6N46qA=wO;WYhx(QxGWN<;R^Jsf zR6L+(#J6zFyI#aqTekGKHpA9d$nV^SXYqQ1adlvNCNn{0JiFVfp=L|4|AQ9WR;%rl z)m^@!8v`&fKQie1^u8^sI`@#SzB?}@Vj}>0xLIb?ryOqa^(PF$DDg7-p(}gs2;0%o zeG~FdSj9+v+57(V>Y16FcRsZ=^5YSb?K`C5{*?-Zs^K3su_TW^%<8DJI_W6C4N_Q@ zL5|w0BLfFu1#=uduHwRrztIAI99Pd7ZzIMC>>?Cta>A;1k4s&as}YJ&_L5Cf(BBBQ zo<>ADr7h6Ro@{m5Z4cV8bh8TC{fq0*+aaL*PWvmR!!^bCSUY#g?dbs}ou4&JE(3Lq z)um2@ry-H&;FVf|cphty*1GJz2d~oAGK(4fv_H7rhzRAZJuT}6eVd`gAAdi<*4ez= z?ah-nm70F~2Y&6WYi-mv1S$(}=d#u?>C_)BatDR^Wwi%;nf?xPT3yx+@NXAZJ=MFq zD6S35@sNgig10aVtZLIQXJjBaxA6apMlmqPrgX-AnN=Auc*)Ale0F@y;qxvmBm~hI zg#k6tXJS^kGb5^+n4${m=a3v0=JfbcNLg5n9?w@EA0H{hM~&+8^Yb4cUE)c9Xy@j- zEh9!%3lO2$tlsY)&&adjT8klq`vnL8($dn(p`%P11;zMHO-w+f68#q~4UHO&1uqj6 zNGCTd1QS3hQh0g4n;PoxM-*pMg%kiehwJO>Zw_q@&CQ?#1r{v0kODlsyqGj<+uPd= z=d*+GStgTNS69O?&1aw!36O|scucIUjh&s|6X~oX1&kCFM_`hbV$gU`gi}s85a`S- zDa07&e>7ZFanOHNR#ad|{zI<;NziEIk+R~g-@n3vmgU**ZhS&QRQ_?+9@b;a0Nyw0 z8XL1@aE1x@aG{*@Dcj`KZzexIa04$cFV}T63)oP5_C4L-s761XaPi>7^@n4NqFB?U zOeZtR#NA#`N?NrpizHK^=|tm$R7pMWtqNMe5V=f*^W%ESZNL2zd#^GeeR<=aFsa|$ z-F4&14h{|u4TTXv0l`!@)Hdvx6e)do&A|sVka;amt+V{^ebKZz>4~TR{I{27x3ulg zmz}c4A_pX~QI`u!Pq(N1+-C}$(S}-&&VTnOiiSgjwAyW?yu98$_pziBeGgpHqsnV?8Pmw>RSsHm&!6oliT8I=RwL&X|_ z(S&90nrK^E((eV-O%->X)~`vMgX~P}8{mM_1qM4j$P#R{BRm_RJtGx)Z3D11!Vx4j z-p~dk)`djhR>6+X930Bq_F0nEr-x_Ck_EdA0X!B=nSx5;!x=ORb@oK9Ql&`vTZlrxRJxi;!-~||hstgN0j)7dO?o@fJzoj3}lp*v&7`MXUK+KS4gITQ@ z>Fe`e%vA;(rXkbI_v~^$?n~6ipdzm)08$K=}8Fd<1bw|5$r$NvaC-p7wb%UZr*2u_z}V8c}?yP zCoB^TA2v2vbcSDDn&t6%B+6#JvyLxl<>1y}a^svXJH^H~EZ*!Uc(3nm$~uC$Q)K%uSnO>~?d=E9 zpWFOgB2XFfh?XH0OZ+8sSoAt9_PhN{x?5WE^7h>hkXZxQ5eJZif2bVAAa^{1ccKo8 zZ4MCXH!d60^a9)#nuSCteO<06K@v=XOb*47^x1RvQp zJk4hHu1m~&*{u~T9^kL_(3T&XSnIfeqAIZ)Wrn^@CN~civ=;zKc7J`#VLmOAlbgD8 zH{D#fCwsd~uGCq0*rVPmQ36v6_iCC-#Z~sKA^>R2Ht#U(M-nJp zot-=HCfkvxgVzM8X8{4!nCi|`u~MdM{DaS zk%G<~x)za%6%e|ZA*#QuL~-91S_C5bRTSNe=&%A|&p$Ws+nzLDwF}EaDpW452Gc3&1I`Bz&=DwV?lwu8KD4~A4kYd9Z}pw zl|Q!U4Nnm|k5m7w1q%|8PG zP!L&hoSQSzNmK3gYOrAe6iAt`-a~NsLr5M3(aa}K#aZnolY$Vybn2tFV<|2Sz;H^4 z{wgk%hCS$T^MC;k@T(r))QwW9YmY@YZ>2GEJ(f0aE*XE*YClWO)FK!m zLs24VJt&X@WlGKy>o+UE0kms1D}a_^!h4-S(}LdB!b8KD zXtMQL(tgMmQ*H6G8IKfpqtl>Bj@9YRoHfO_b;fhZ-dpp8zB{ofC9(VML~$o4a}p$2 z7+^EA%-S7};}ki_d48Wp#AUh=RaEh{5J3aN@dQfx8EDAK$(fkyWU@%0pqC%;1Ra zkB4K4c89_<>&9c$Ki@iv@vMZ%mnEu^^@d>fy4QZ>|oNL-kug5WNNGy}X zkuzf{dnu@NRDA>{2+e<4R+^n+F1OWio#KVihqtiz3$i=Jfo#WiT4+Z-luQ* zMsh)leT!jtJVeC9!voc?+!B<D~?!w22A#LSV`8UztZSs-+=Is%q7D~{- z-+3jsf^<7sDQqmvV|mY)@+&$O6w=%;z08?Lq7esZLopBN7F{prce^eaD8+5><&7et zzxRehf`eNbxakTLaZnTe^Q19aX_@c=DGliaHCBgp4qZoYpQxayW6M#=_Wks_hI*#4 znH$D9eSLlWU%xbDApX`zXR-X?`aZrQ^>PqO$Vy$BCK;|jVK;KyZ@>rwI-GCcHa9lB zZ}&&q+B^zoo@0Uq4N=FUtDQV9i>x1f8OS6AZo2>4jV$HPolIqMrz9j4D3ui|oLKL{ zg2X6a|DEqhK(11m64it58rGGq;OLrz#C>{qSKk+?flv1T1Z5DXQ4}{M?@0czKa?)8cj`2M@Ppmp@uBDAhx4Mqe6uNc|-5^9i)B1fF`${qocK@ z-VdkFcz9>)>m4AOXH%!O zpg>4sbYXRM71S=QuB>c@2#1U#rDbLD>i>P--#3B|ya^2!=R)8B--Z{5 z#Fp)HysVyRbGK2Aa3AtDRM zwA3tyo_LkG%QqA&9w<}7?fojHth^9UHsa#)2=c8VUI}2o5>fhJq8iY2Nw8oR*bw&| z#?c;FksHnyieq3TnNDR}nwzt+W1Tp)feikF88fCdK#VRWAw4}gDTxfzH7F!RMOpdb z@p04Am!mi1@i|?u;zvPYu!gbtO^zYu+~8M8d2Ma!_`;Z&sSmDq*zjEfBoA?3X)TDL zk>xp&S#@k6uova`I7mO(2T^3Y6frJmE^QSRmz<-&o12s4;}uO!GUN%2X*7@mL4w4f z;6b_U^?cDzLs{QZT_eYHKP@gv#i}n8p&wox2fNxb!uQbmtDn^h0IZh^ZKN3IKgld% ziW+#`uAWZ$tNv214?_!9z0BcK1cE|UA8A`ihMWes6gXSoDT3UY(yk zD2*UhfUjS!ILg_sW~<9vQ#8~F#8;j&hDlSkl0UI$?n_$7njBTnS#n+wx!u4SI1!-< z`pgawzsHFM>9YX2GYkPlcKH99(WXSOf+&y?19c4z{3tyP=T$R7!jsuQNfsjm!D>qA z)N9Q~z>zVhX{?LMrBfDIIiH7wpWy(r&DsR4amjSteJ~&z4NVBjsCv`O#ef5Z1x<5= z>K%GI`2-NhHk-e13Z%6S-g+44u)1nI!kLkN`I)v~P9PVUuUuJqo@IIeVAgSas;&JA zY%|*2ELGFB+HF@>uDNO}MLs*d)!Tp%j?iy)YptuqU@7@^lySo#=&+9Pn&GP*H{mZ~uKz_qHm3d2!D1Vr95OS5^r1!fW?TCJ3c|f|_kmU&rloZf0xyx%ZZKACk`F z{-_=(Wp$29?J#vl&4dydO*#VF{gacETUylO#O4I785tmQ@%4Am(4KT=>h}J= z)4%tZ#l>W>sHa1W2Ig;1Co(^jQG33!`#rd6Tl{JTorB1#VyJYHsCyfM_$8vCsHE^V zN`f|dS$fr8bEZ*t8TG5|Ug&{K@1Esx8B$~6($=<}dOQAn^y4AJGCQV9*Vel-j0HJu zNB#4X;>bC-v*yYBf2jJ(s5rW?$;Mp+!F_Od2<}cGKybI#3?+xxn1f5D-s!03D03>vS`w@?-=wRONX+HwBe_>5Hyf z@1Cy#-#h$1`edYt0}b=5kcDztM3+Mq3eJSnF%6E>0ReSTAo^$jN)Qb@C+Io ziHaWuy9){PKDqw0u^Cr>FMa)DP?3T&Rz~DH4mU%UDe^O8Ol&MO9o?*Dv+t%BiJt4- zz;z95Ldrs!m3mzF+nwc~DT$)_qYS=#)gk}?17Tp1`>4L=6fIZ^z5mY#1=5=W znvyiIc6_f0)Sq?j%+K6$`}a?Dt6ocVBYr%K!F(J@;$kEF{(=jMd?!SnD8A=Xqfsov zfQ)QL!E<7N9`*}CL`vMh!Wr#ZKOhebYWGw1!y_ZLTW~v)@ZTqe3I}NYEwp+fbQhVT2`$evcThJ*M70d z#{pQH?;9u^M_X#bi3O`DA&P%7b-X`Zf6h@!C>DCVTUh+-W3vhs%YQKTlFMY%af`Hz?GA-9Y5r|nP@m*#PiINEXyrv*)lBR>-K;iMB`UA#3N80*Vr za+pkduJ4k}X+j=i+h2WvMwjIv@u{CyR<=LlVS~4KGKsVM-*4{Ng&J08zViFtBAXAK zczz=>#fvlben?iQqo`=tb3c!vkGS-8Ln@xdbE!ySLX{kjqH0Wl)*auHy6E1EOdk8S zICCviu2+jCF1OQLv;_Oi&c>GGbu%IsirRfWnEA(`uF{0OH-0cIb0@gquhER&xWPb^ z8AjjFO8lPSMc)Vgx1g~>lXM7^xtgw`i^JN=j%sZ#g_J6}(&O&eD|I(qNQD<}oZ!-E zJSHiCy!+?dujCwb@v}_s{Zi!7pg9!Ju*D<>6ta1>WEnw4OdPt-MN3?EvvKZCua`e? zB+g40v}bV0VuwaE2`|H|kUIqkczhPtj#+h{3uJn%HTy)Z3@auq`uA6bI8OY)(XPuG zL=X$Q#MMh1_SK*j-}5Y-c5dg>hD_?pFQ3~%xAs$>uE$h=S?N38PB7y<=5;&4ec5qq z%Wb3)nMFF?(G#T!?PuS^BXZQ4AM*L=eA8Fxw5Bq(5-QE+(0|9Tz$FU;T2MIDCb#q7 z`kx-!`>4qapBczcO!^-iYNy?VZX*k^0uNcclP}z9tl2;5M?MUtWxdY*vNPmCmV{uY7FVe#kSSvVgH#lKnexOmdw#; zqz?K17@Jb#9-qZ{o4*nj-Qk|)>pn9cx@k|xbU?1)hfbz`xvB0$hUbOcIS_NHZ&u{7 zks<-0MXG+l=a!H$v)o(xZt#gQt!ZEK+`IQ{zKmEg*Ze-;E|tXL6(cQNw%dGCSD)Qt zT5qZ`n(ah;FP|N z5)le{+idYhn zpEKi(Egyme-WQ3!V@JyeMxLj2N7_Pjnye-S&oxK`06Z75=i^@z5EK>oG7D3SA;_H1 zo0n=d>enwX*B$k+Bm}*aZVL7ZiC|-jCG~qR-XI*8{D;S6KtRibbY1@O8DVbN^0;zJ zPf5GJCX_*%+pd6JH~ZFg=!f$0Inf6VLbwoCCoKwFy7gohFF0RCygsl9jHjE+HX8EA^adz4IO*{-VlcXH5`6KI*GWJ`-hs?9CA2Sjd7QB5To7I6UE=`M09bx zFy$XfCnBi~S|-q$e%~5Gc~HG?Cvh_S0GYzWzYh0RAq8F%UXD7wVOWPtx9UDoV+)Bj zKTTu;7;CAr1e~`@eBW$r3{{@zO}Qr&nQEKjpH*x2BHh&8++JFP`aKjbr31f}>oonC zx!LCi2TjeDVo4W!%@1Vw?~2{;1Ja)|&uZxkP9vmah~sM%qS+}2GQMOdL`{$55R7pj zy6)FZe-=#_G_!Ty%^^Z@{W;;QfAfNev6tSc=lf%%OkfR-CD5*OKclnu?~S()kZ5J= z_1*|}DNASmygld5fy?o!U7U#0y}PRBW?X5w8GA~duzbFcM)To^E)o@SF3`lp!~u1Z zqQK|#IvqGq2Qz(UAcuwyrhy?`gT)O9k{2HZM1nA4)n23y?Ag+*=DZwbS)I~a>qZYz zvo7A{iQA9DsU;zc=Ynqa-M6!~)P;d*>VtLnfp3vBSf5PiPn%>$XYfXEQe$A;0l~8= z`sywa5geiSE;dc`ecs4u0yQ-8Js^4TkGA-Z{dcJKyEmi>jVN~EBMwJ*2 z8krLM*qIOX7w)-y%w@_HMSD&~0 zJJIr6q+CR_dA6B)r(DQ+JT|{PyQKunU2Op2EkypKbM!sM>N$&$ajgf9=kXN7*pm)^ z=IKhkce$g8Q(Lc#F&>_qqd7aQ1s6dgdNK$98Khb80;lWwq|%m3vY;mF#nlXYvc4pCH| zd!yE-T+Gp6#@hN+Wm~WtxoMcXZ!(H#uz~p$A_jOy%`TH=p{_}_B6&R?CcFrsr`hy; zQj?nzzuo&WrNEDY&Ow~No^OfWI;r(YxL#=a>^fM%SzOD9_8KnV7q5rb^oK!*d@+Bv zK|KQrywkpdPTre!u-9urCUqHV$MaLor%?NETwZ@7=!eAND6C~1Bt%_LVwm+el?mAf zP&cGt`ADl1;{J(EcNgVM>zoX`KSSOf`~go=U- zqrCJiDR}Zlz&X}3&H%*d$aeEe(E$1Nl}(Ne@_um^3=m^fn5a%E7sOo67KhU1{L}ze>lsd}5@OmVSK)*T1mH$o7x-7gM&A z_RFqIAEqFKRnorv3}FeI%2OQ{a@Dn;^DM%eiM5@kInOIno3@A8p9D;v7mQB@KRie_ zKZSmYrlbtH`##_54yZZr_^IMS_SmygviE6fo`g#eqG7&e`*3)a&mDiS>9CtE3Kz(d zLWdBC2~Xyz_gJW|y`joE&0hl1suQ4O=(Q0xU_{z>dSBD<0zgu&??=Axdk;c^e6sy! zA{tu6;=`m22sBCgR=g0GmG!z6h!#UEfY|5h`7o}D^s zo(}%2@yv!mFd1Mo8dh)SYslm2?8#x@1-0h3Vm++<1u*wu253vb=n1wfV*m~p^?V;p*c26#`omd?Qct) z*;f|$2{7-xfleZ1cdan;)9u6C$=k*|sF=XYsscZoR_>zHvhCrkukHYpQu?l4tL1@q zaQn~a6-v+~kvB66Si1_A-CgC01WGqJIhD>)K+cZ+D4by_KD{2`f$F#yOBPzMRuwE+%RbatDS|<9MX*t~CNzth;t&)>KsH$m7F4c=DCXz3%y+oidSU?lZ0 zA4nWaO?dH#V*V56BMz55QSyQsWJJMd`LIou`RW{gQJx*m5^qA3ERcP=7Re_9@EzTH zx_lu?f)<7#&04@mAXDmQuRR!?F;=M{(j1+gijgiv#(awuOo1((YyJ6XcWxX>Zarc{ zoK95wy|P{QlQ9=lhDmcfWWcoPUDju>cSk->m){sfjuAjZR+GEm7eHMz+PJ8~;k1q9 zYjkh=st2A#ANImEo=k3SM%`dQP5$8Kc zTUJYr9(ZAnuTvqIF53+xz zZ=jq~lU-;20bA_!m-2D)cxkFo&c@wrcz4cDn%jrWbU;h08r(XUy%w4xEx(IIhMvi_?c$K`wzmLJ%#Gau@DZgmrk5z{!CVZ6@; z&J&G7r%0v@o)BDAS01NECeF&nZ%F2N36^#msF&rNYT#5;D5n4~FZ+#)@A=`hZtFyp zDM`E<6xixgkL;wGzIwxwV=saA{;M{=zD{Dw`b!d`1p+wIp*vpUIb5y*Z5K;o3*NdI z;N`&4iwlac{Gh(iW0m!5_F)dQt1Ou-%|H?qYry|tgpdfMT|EUHE98HJ+@NMe* zD);{iR%HbBUxsoZuMiUkR%xu%VNr_OnE2u3)iHh3kZSAzp<&_(f=`etB|nH}Lnxa4 zWXbMk@XfH?Vfw7P#RFt46ONRNB#VzOYSsu|6|_pV(qIlqji^R^w|YL)h#)OT6^(Zru9ftUi6>YMs-WteQ zA!yPTP5Fu2vfBxqq)|(ywk+3YcM7o@_S5UQ32gq%Sa4wz`Yl`pLB`?zd>2aWX+Kvo zAuvu?qGd8ccK7z+sVod$d~Tik>q84aNBOP`-P`$kZz*}7`irQ)nwpN6ROUXFhjPZp z9ZBiH&-$Tj)fxODa$B!iI-Mftiy;*coS+A5nw3R&cn&+k!U9&;v*n+col>Q95IuO~ zxL>w)B!Bnq7ar;gxT%t(+FS4Xc5UcE0QI{#oBZbR!Um5OYNwGW(#;mz3*1jPU98A@ ze#x~Tw%QBBPwM&{{KQbhx*yk%?Zrf&F}?eq7*Rkndaf%4nRZ=IznSikp;>q|c}-0s zWUKMxOfEPSd_3k(bQRvOG@EG3(tip4EH>MOV&*>vckPA`AgDu`yAEUOmpApi8Z^1i zW)AgcyIc>^?kfxv&CO$5zH@P3(33HB9R{~9AH3wgkQR-mr_gd5gPx;qHSlR7GQdWJ zXl^EeCxBmo{=*V;7MIU0jub?X^6Tkb?FX(&)6!JI87D{Zw#e5%2j1q7^&pU^Kltll z(TKgC_EXuB|4vWa@8m6=o+^_yGj;tQ#I|Ea7e7qx%~P8s#?I7N*|1nI|g4451M&)Qnt*ZF+8kz*T; zzH7dVglA7OVCF0o{Jn^Xh!>rY8?JB`85hcA9l%dSU5bV(GvmXQIr#kXqOx$PEJ_#M zFvUc68kGu8PvGkq1YWSH4=i9Ex+vs6_ntJ4=O*}?D!xl^_cmM?^|3X0&v&W=0Gqy3 zl8}ZC(K0@7T_ox?%gKTU4@7AE#FgIf3(SvltXH7tpj&q|2_8aM7gF4_Ys&yS?cWWP z4jItUBJxCr3Nd6b7(p>s1X(cq7;|M+d%GXn)TpYqe5x=2DI!Gd?opSWpq4j?l3r{i zC6&w4h*MvMxdeY z@j10x!*6pWE;sy zXUT!+aR4AfSQatchgb#OZ(BU$)QdA|65KpCfCQMPy_$Y!>`MT>|GoYOAv~;{tiQ6J zFq4*+Ohv~R=uL2Vv zJL@7GvA^qUPya)=m!uuXjn8eUm|%2_S}^nz6-<-71Ja49od|=$`ExxhJd|7WmwH5C z#y~0|L=UReyJUyNxubGd8#!Tx(YQC|4>^^tefTZZaq6lSO=b-0_2qA`s*>HCFeT_HgVhq`ImJqNJS?JpRZhS z%;&k=HM^S8u6GrG&7qxV7Y5BixBMwZnWsb;uh;>+E9{VD43__zIZuz|$G$Q?8lqhzNy~H|cD|c8bJDz=R(CtcGHQ=nw z>EOYrt=e2l=Wu^@Ca%j<<`Qf~`I0xj3;uoq}L! zN%a>6;V3m@ng&P@@H&rh9?BU#jGzDvSn#^_E4+`!Ry&CvLP|^1iHXVwpp`|o7dR&m z-F^yml&L1nNorgw_F6NfQ0-nmwUSN!$$7Syf-f%4+#oJjMt8>==xA$kXbep(-=i-b z+8Y)Dvhv|`4xwWF!`o)g#O6)mO+i<`LJk_^>7NxYML z|2=E45I3cR)lMo$P2u_4|H)ofu6O!q4Z7KQU2047ccFob%x{Iv>bbuiBADn`pZtR&~B*62Qz z$IBElzSc>0PFXQfpjscq^b4^8h3|1hhy)>=morBdzXW# za}0+!wn9b;&Qy;vRXr#{e>PTie#Vc( zbouLy6z;a0KFm^kdBd1#76UQ;!{k@2(wlkd+{}$V&c9m6?3*8dH7H=&1~@Hla%I;a z9!C9`!LsHyfn02M0NoyT;|pOLuLenIQf!oR)#_mdJOq4izBfuM{zO(8S0o#Z-aoP_ z&CeLXZ_ZF%odmca7IEIKTb6#IJX{w>D&2J|%>1>SZ`=;B+L4*f_4!Pi<} zKl9l0{5|#VZ-9mYra4{|^4EsMR2mb-AC1br+P-3Fqkuxp z%q_h*KIAkB+K2F&=O!?rMK7X>8f*XUB8c_T6*p9xh_M+-m9!#S@x_2z4mGL|%hH;7 zAT~|8D1UYm=z6VQ|KjKJB_`nHRn$9BFM@j0(j1Z{M+x@u8h6;mnVGt>q{OD|Ylc)G z&2p!5BF>SX+d&shS3&>d%TG!&QO^-uX-Xq7`mZ0EXcxiPWu7FP#)Rmr&Sn1BTBk4R z46=+b-Nhq}4{P6(HDJhr9T<2PM$bW)pRO7Ou}>7TQ1oHB#ID|+zbg&9Y%v;;c~uK4 zY@E$YU1(8cgU@EeuQ`R1vRgUat_lmbjCXfRtdhHlYix}AKg|OCw_-3a@+DMD#W#zs z5ntk&S%(p|P%Hp@D1a0@98N4M@&F1qN8U(VI}rmvi|_2R;a+hY`p=B1&&dO&nYzdu z)XOV_=)oWInB4m3Y8HNysOhiXx-NI~g=S3#?*CT{pq%}3Eqmwmo<|h1iTaf;vtY<} z%4%yRtY=2IBkj)pZ&to+j`1r8=8T0co5PS`X_^@!MWk02jy1QSL*4KN>#40msSm?N z6GX3X?j=Z}?I|1@7+$!M`?jYo=XG!NFT3z8;SYW!GSK%;C3?iaM^c@@f(*fWhBPr= zSQy&hX5F0TV<#w zbh2vydn!7idIMPdT=y=+R=-Pcm8vWor2X}-s=-XqC_d&GA&>9*i0D(%%?Us~g*s#M z429DdefqWb_x9c&wgbzI}#{B|bX+l2uEZv!G^6dBo0~v?HU| z^Ce47JFo8sAqePCEWtZ+pH>V4Aeyw+KF#Z=mi$1nBIdyq)ZN$}{B@3etzBX^&_b*I zUAj4G`Wr2VV$CW)YbJeIsVc&1lKn|Jt8;@F^f?m0Lz^q!8aDY%ZJZX0d2Co>R}w90 zj>m<9c-nHXzF50N)DG>?*H@dEgy^}eSe)jS<^`DzCfmlCe0D_>>!-q9(NUGgFrxRP zv|`=o7;L`XP0TkG8GN5lhpTxo)K`(PnP$b6Zs%oF0)4N3LE?7gGGg75Tfu$F8?$t7 zfvL%#VP#%(z@VZQL!y2}jQie&6ZGx}#yMc%lTF%;|BQ}tjjZ^BvFS<#)$5+FNV@N> zN{@g5$bgTGZvJ4>wmQ%SEt+}78){~fFC>2nR2yV^mCV7vp0xHCuVi$ z2+2NMG{lAVYq{9)t=ogsJ}9mlMV3CflevRP;J8D9(Z!xlB4IrI*c|ZHZlS?TVt(}*b zmkV51R95ctFwxRltjrELB@FL1T+-MnTvns>!uDGom|I|$6MJ3CW*cc`$v`e#49~tcEK@Jm9McT7pED9dVddT{!>=dW(Uhgo?!9*)hY8bg+8H#GDaVSmn^j6sY z5xYm!5s#NJU0E4cA{AFgf4DBpi>NlFbz19DK{{+UtdpDVkmW3Gspaw++6h?giem&1l%oar3L!hD!P1(PZKLMkzE#L$l-qZxQyjw=*;jaOk4qEks%z)(v?(mcP7!X zrVjiHat83iSOfyremJazjh67Wu?XO;I=*lgL)B1Cx4|d&)I%52DTWugm}KPCUe}j0 zO@R>j^}eD53(qdD zo?}&z5wENyojrVLYg-ziS=vq0v(*lqGW+acqr`m_R^{7n9$^FieQZT5-RuMX04uEKQY! zNzVOaF2If-0MsXCy3>C}zjiHLNitDWnH^VQ39_k?P`!~5-+QL*-m8p}q#H~uI>5LZ z8gRVsS9)rC&d*V(Qle%QV@cZGdc#=&xLMe5VVcfY%e{mHrJL&BW;mth$2%tfuCTJv zh6KyQ_R}Feoh#=3P$AU8qVPKl9ZGS@48zkr&Rho&%|Lr)jeXt!kVKFeNjs^>m3e`Scz>{EzU>Ixs4EK;M zcU!Yara?D(Z(QrL&U!fPdr;xS!j1X+h1~-4Qs=pIZYn|+PZH|-NV>4L?RrH(@Ux-T zH|wYL5zT|-=!tv6GkB^utBB+F4^FSPwJ!Ijhb5gC?PLt4QGj$OwxercdkE{2;cGi* zdd_us2rR5eVZ%GWYQ1Y^cPWne&M#7#K3%)NDh=-~^) z0`^U->QfPbk`75p2%Smx(R)q+o?b zHL&Vhkr8_hd0JE`TkV7=JBBHnW$RLf4Kt&=JC=@p*xZ^#m0jImTz^!7w)iizQ$T>I zMy=?2d?pN?aVXKqg_)^9i}+&O)6OBY&Li(Tot{QY(#c(STcwYR_(R` zMV%EuB99?E6@UH{@dDrcZRU$gMsR6g8mg1}TBaPqlkK{6sVI8?Y<)-rq)dloi1r3izj zKU5YQd#~f>Ma>80lE-6j(U7D??AwV|ZZ-CH6qy(38PP(wk9Wvsm?^sJ_cTZM23tI} z7Pmq(Zee&qm?3VMl2cj94>6yK_lytn81)j)r)?N&ihrzZ=vJmcJ5^YUPJZx zvBKF6et8IhCtN?Ne4!bIU+T6hS1F2<6msYy%V6Z&F0gew{qyX#Sj@$faL33+ozg7| z{ZG60AJd@-`|a~L;hF^1yzQ?T z34zLrNeq3(EjhECaAo_HPIfC>9hHCU|*QzFQrxmC;1pz==YV*^zjH-Fh7& z&$y-F!UJxQQrWIAIV(^YmqGwuiXS(ZmX~-0w=xl7!sCptwuj5Z?3Oxs!k5L>Rq8|SO`R&VpJE@pJ9zk8;4xJC$aT%Q%^#;!h`xm}DY~V?oB`TCiCe9OYjCU*1K_^C{WgwQ z=r41JnqXs1LWY>p*2#-<%4QS|5^>GwCxPGN3m!eIB!BK#To3_sHDq9H0v`lpBt@*8 zh8W&S?WIL)Lx1uvbG079v?sHcTfCakLP%@SQK;s8Y&M3Q7TFgs<0^Ph^UQd;3}zIifpmk_jQiVg^Sec;B&uJ6jslw|&=`NaIT(xzuizJ&F** z2?I}|N#`H^m9i#^< zz2;bOS*0>eLAM;39vB$*y~J8r$rCUs5eu5D4dd2dcxelYE1!1wjaA+M4P1K-3pkqv zAR|d4#yb9vn4yFW$vusAm6SwnVVJ%R&C>Z+aeN?dt?%R;-CzEFU0@YDU)oz^^^Zr2 zbahDMb{OO9XiUi?4&{ir(;<9_I|-gP312V;7UR%J+~04vbHfPY zgZ(1bY5RC0)oL)-8xT0={b*4O1IKrtJGt}-5cgX9{9DM*Ab>%WA)k)nyM>Hd^H@nm zfw#1487ngyTaV5=ZQmEIa+J}R!OXcNX**TaWNC6&%A@WB6mLM-dSCwNtN1aweCOYS9V@x4>=?Qsm(KeWhi6( z_gb4^WPb@wX$(PRQS&ImkMC}L)e^vE=iR5U+B&d1i{E_9|BC)wZ)5iT4;5;3tL}cg zWpv}vB3Qe!b?YRRy)Kdd{0r$kCWSs|7>0M$_~m>HL9p(is>%XjNk41Bb5IHEDHK{t z3V{I_`1CG#+8drBBb9Fl$#3uNQn2q-Th_>B`ZUSI>T3GAIW?WumXDZYepd*{4{@X% zK%Gbz#@Ku-j-#XBwzw-==8}kOBQt{xRcR3JG)>D$!WhW3l*67AL*PAm4!j;!I527a zRv94^{r$&Y2v6r~fvEH0SE12QuKjqQwRG&3nk@T@L`tqBq#cA&f%@+gpy;|9{-a$8 zfFP?tVXLouahizUvf)Px)d++iQjib>&jq&v2K%fFo+UE$ws7%dUSnc3akMcge|JgRVa{vneXSSl$m2=X5xuG4&7Mp^xAg>`Tpf0GE}c72#%IM6&1_G z#EE%}=w&4{zv@#K(~{)iPO4;2B9spx+dnFAxbzHVKA%T{@L;C*;HxU(rQnTRTbLxm zA%^Uj9#h=cIM|Cv#u|fqXNZgoON+`bpUO)n*E}LM4wxG~JQWdcc;w&1+;xNrBdyeWi?s6bFeo447kbntXntiOTM_j&Ecf)OQ}sgW2$ zGjE#!#YhPBf1@6>ZpB6(ElNbgdin`0bIb3vMv5$d6GT&1dW#evpLhN_Xh92)6IG$C zh<&r&USTDG$|U<9zZ>rDpg_eq(($oS%X-c*+5v)x1#{^h(}H z2mlnHODskSyax0jI7VNnwL`2RSU4QZ?k|n!QQd~ARl3?(T+8rLh9kOs!yv)CCO(Zu zViFS-&ykT9%*QISm5vx#ws;MZywYey- z!$lhCq-dr>b2>PVpFzApk%@SxgT*XSxrwIAa?%e^V?AdE2tPyP5KVoeYD?G9SI2!T zBxATr^s;?=^Fd#hwJ0y=91?+c8Vk(;223-#Z0odLxeU>P92K7wcuG@=+6*g1*du;| zL|jI7gJl7vZ?)kVx7PWjBE`q6u_iL$664=94X&ncG2B88UGMFXU)4ug;^73zuL?*L z3TP1d1OLHe!h<5nCGCsY&Wc$v!Ev%E9&1<%PjtR`r*}!#s6k%aC6J+&qsJAu-0qAR zR)~3ugQOCA|E}wHM`22iVVAye+l6yZB!=2CM)GrE0zKN>8zJ&I5-LB}x5Wc36H@e4 zS2w;yfK1&cqRQ8G9?T4(0o0f2{7ObES2%>)|qnpp;Omdhnx)c z2}!-xgCAS{(OkB7D712OYAaC^)-*ZoILn$^>9NbV<1(b2WSq^K`Mi3EH5S88~I8)s>svzroX}(5hhki4A zRaml`{7`3I*^`B-8Szg9*SY&eEQ3%$+2Lc<%Vg(8BBty|eO3iTjFdVKES zKXc_k?cleNh&c=gPc4r0>q4JjEDV_NEpc(-yY$iXlxZqwd6=~y>Z2h5I!qtK_CBP# z;_zG_xf{xGTQ?0Cb=3R$?n*9bfb^eE(#aF;;H97q&wcL&3LldeCOhR|SB#pVfXv5n z#m?m!e-c}xt&D!!mf#7XgVjRhQbmV!yXDJ0=G=$AUuv~JltE6Wn5<2}-z=8TUGdI4 z_PWqETRVyeEbBr+GwH|4zW!7*aD!@WFG-wC1vkq2`av!k%C46gt1iX5nwb#5?`F-a zua$huX}E~ARpNgk?BVe+ic=_($Q31QU50W3Su}>xWtBib5;6IaO{FmC3_9e1%(MKjuE4|d)HwPYS zxl0-cHJ78GqxJ*P*o__K&5b>+-cqDKO&Jl*bT(X%GbxKSQzRD1HMkYB{cF-<3M#|2 zVE`b%7bcZO!dO_R6s0N1s>a8sM}{sQMVN?z3j|qQ43U4mayD+hff-R1qvT@M?1M^E z%~PUnPy>ME7C$&Zxa^w!0Wf<+0!YQ(NokSAfSq?E?zUwXWwT$I&V4YO0%|r|_7m$A8BNCc*zFC17G=3xn$H=^%SBXH^`jDxF#96rY_N)pP{wHvn8$zONQbI z(1N`fbIGwbc6U-Uut#su0W2<9Z~}YVcpvQ-;Z_guuAu z0XEsu*I?{=LtCOS7SEPYxT&?yADskUoY%j&vI$R?nCJrw;xoY~g#fW4&HQCN+j8Z` z)M8}aNkd9})pGYe|Ix%w8NH%z#zW#RhLyTj2Nf}z&AIo}_@ZrV1D?=+lIY?K^3ybB*#oG>e0HT!X(#j`CU%HVjOuLEj9o|2#P3bE5x_C%D z$xq^Bkc#0Nhk9W99Qort#1v=a{jOEr*xXgO%@vHpQ#iMiRfkE6ZCWp%5X6V$&%9lJ zddMD$>!caDcsTKGKe8>D>;9tvQpk{eSB#^7Dmx}u1xK;)^=5yCYU>C$R{t&KW>iW~ z)SNO@2S<=oXZc7YgGcCSxH}OgAWU;J``MQjst-`y`_wzKp^GuEd(H)o1Xn-PI| zIC2Eu>(`G=++et%P|G%BouY*^nk*Fx72JTT8YGOgTis!$Oe+~ua)$IU5etH=;rBB= z`O?bF0&3_T2`ATs#*|_#?4)LrP-kE19SMmVjx1m%H}Dfi|2mvT6XAy*?q~DUP`ig! z+(6^*`m4j0{q9K!iyxt4t6(Wy9}A)QLDEAKO_*J6ZI$c-6F!FTVgJ?5!aZNcT3N+^ z18Xv)=OALP8Aof26_I7jUSe3PE^0V}Ek@~T$WGT^75W|upTK5sLrbL~#XPu#oI6s! zL%vU?;zE7!5P{ERkoJ3VPB<1UL=*L9!;2;f`p9<)!apBdrzV8T&}32D-wF4@#so;6 z@SuY*+yn7q{3XbLU>j*x4{pe<8y*F$3g#B_EmbvLvdQJ-?RN-2M3p;(6D9cifbNaQ z= zxM@J6M`X4Jr^IYL7==kGvqb@5Ul|KFgssr#ElhnHCeE3m{~s6-MFF67AV@i2M1&5sQ<<`)AyIiVpFT40Wi)AcCWZ_*M+t8QEzForc)oTv)X+;sg$Z(jrv75<# zGo#H@-;H{=b9LTvpvZ`0#te7Tn7UI#BI;@=wmMor;}o~qIM!jxM~qBhF#Stx>OI3w zVbm7Jc{xTkk@=-X4!wPfB_*E1PB8mhPSXsMpNjq z+SZ7U?p8cHW-6R~Y??%ja6k{jI>Y4ybE2srBYYImXLfyR+j6^2tMYqTq`(GVT5&nu zc|=hOQozSa!Tp9sOrAyOEO^IKU#DXP7hyky2heCPWhEr(bd38J{Obq7Y$XCOi+(aR zb@3@?GCVNvx!_K;I*Wc{Ru?yJ;@v_B6?BIXA_Mw0Awyz)w`e#j_sO0R!eF^fJi2g0 ze^ufE|7#uxLvFTc6T|#;lTXAXf>Twfh$9$8QD2J-6q6|>Q|n-rFij~d;R2-DghLSQ zbgalh0s{{Uwq$x#C}Qts4~q}hz5Hb{NEKD!k=5VgZx16%96^i~gYWkn9#VvKuk@79 z*}umrm&A1wzgAmqCEqBZ?m%Pf={iMSsLb~0?1{>L9ge{AGR^Gmhkr>L6|BVo_2N9q z!_}69U<$SGUP1p1mt_7ojewZ;$LBQ*LqGp^CdD$x#=afZwVRB0^#OFPrC$$8+|1De zpT#X1@p#0H)yL^?zx5gCe|-A&GLJLa&pQ_LOYn~2wtUvd^o^ld7A zVSdCKam!n~gG2O!fB*jO@<$1L{BTwB%}z<0BSc7uAe{O6DCtK12|Pr$exUMSSDu&S zm8YXXP$R+OdDTt07De{k3U#jdzki{ASVEjy5*b*PE6~@|eZH*NQX#NmR#b2opj?(W z{z3-cL1DO3y`KZDbxddYv+dc|);TKEQh!L#hRHpeS8vKd)HjZ}hjJYSj~gOyNseU@ z2uA%2mhUd%o-;!W#eWiip-@uD|29Bs-e^yX3R5-!gy(cr{<*UurzZtP2p7c{J<70qnz00FS>mRvB+k zvoi_0C>3Y8#>E~c6JaBbz3=b)B2Uh88;dL!FQ+iD6B0Rn!35Or$%}!`Rt|6Af#dyc z9E+{D=tuJljzs;+*eu{@>|hBg)#D`U6lW{}1VzyWMAk9><*ZHsJuNz_B8nme2rw|D zWj@hZ=>MiH>xFR77wl<9l_4!s!DMs*_#sM)gHn*zo)<_>zGLLW6YQ;eA!cl!k%{!w z{h%b~dB?+c6pchsAcFvs9LZ&4>XDbmg_|HBgSF+RX=K0|gQS?-85BlMDb^NQPhwS> z7PY$x96DR$={b&{z@e5aL`htq?l6!J%mihZsbA+E%Eh}SPn2}(ejtxZ1R~$wkI$Wg zbmNX#gPP_ZMT2*P1|>IDq(p-;EQH+j8xDp43WNzo zz+BoLA5&RvxO}$#T-E}HQfN*JUf{&<2#z~$K zk%Q}J`)R4WUSTt+LgQy)W#&(qFQM}p#%f-=iIJD3RE?O~_Ift8qG9TIhCL=m!^nab zY0}OO0yR*6=n>J)OqvZm6cmLor5P^g0+EB%S)Ss=>}QJv%#jfaZSVEIHEGGtpBJe2 zSyMlrDpbAET-6>};WK?sBOjSZ-=haKN;a-m-y)kE*h`a+gtER?!~Q{+8-Hati`pe8 zOaC@Oyhe4Q6a2+9!!V6?q%0=97ro_iS9V28XbbuP|tK-58Pl}Z&st^v{nqFLX_TNH>kV3vi4{9cS>{y%fPXK_Y zau}t!)_H-Xu7n;Ae^u=nWFJ6o55$}EDx%v5^a~sC5(6w*{TNe@kU%d2jR^OQeE=}zkue}- zj)P_jOX6LvSPC&^!~4UQ1@MTV^DNfHeZtN+0YL)F2Dsm$d+ZZHEa0yqX@lsPiPvX;>Z2W@l4L59+}u*wrtK`A@d{nJY9m;`g*q)4`4UZ^(?_f4(7hIA$~*oN%gNyxsHdY zHDjks_je~|s8s%cf09cke0{DG>&6{-6PXDf_@53^68FD$zErofS8ydEnPuDBN4(!o zEm0!l<@GkDi#2ZwJ?&%^eDPUM7J4%sMSF=TM8LC&}ZD({X;Yp;(xR z#;{Q&?6_V%g^R>5q|$wSnE13vZ1dYi@1Wu`h6w0PF{|XER^ZM+jQ<|ntyL!o@goa9AtVMj|@mFop18=_e3N7XdV=?N6?;m@2 zD*%|XCf~7gzM7Kdj7j_H@rS=Jan1YFEhCbw{KZ$2ahd=7as8w_- zp%4GNf5^BDf;VR6@c(}F)y=i%kx{$ENzNN-5O5M@j?>P#lJ&c3w?mVd!TMb8RWIP- zHZE*xv)WeKXdPg+m)XQ59UTZWUQ%J~nK=poK)8O}p_&IqkI?;iz!4JC$4wK8w-)*V zbgl0rLN;gl!xPv|k3IQK2*oXb@|k6`c6`2dkK&0DDuvw3=!OrA)sZ6ynm#FznKG03 z)qkr7$U5~5#%R-qhaahkXs&$dA%+H36yFQ zfL2L-`>&Uq#JJmEca+6M@ntSSZ@eJ9L;K?^a3v`wJHK9NQIL2b=MT+6!?;D+pwImX?h(%%*=7dUpDMJ z)ysq=6Xs2c-t^OMZv@zI{q}=pLq?BL_>NVhuQ$*Sqhyrg9R zrn(@#7S5SJwCd!u2IhhQzp@UwMgs!FkhaI0=SM6a6t@4`%)U95kL?dn_z3 z@%rIMAsNA^mtXz(NJi1X@a5HoV-IrOtR%1AH<15udCrylD6U|V5Ec^hPR}#?{DXmk zfrXRj_Pr~gKR-Wl;j@Lc##=_)$NLxWVDk@B*M7vH`{vlOkAMH6jnIGl2FZJWzyJ7- z^*p3szkdGt11XMvfBpW0iJ6s|g@@zUr({ z@BD7QxQzIU3HkqTHMGyT^Bg`jBPlNU*`4mZ*>E_Mrj@Hi3|HZD%y!wz`TPRN7hF$p5=0`-H{EGvy@$qnd zczyljw~t>rgyq=S?=gI4U|?Wm669fd_vGzQ1}U66f4zUUa$?;!A+5yP%7R#j%C1eY zjQ-@=I~IOclnLNJU*B(;-nfTHDZZ*QJJGweW-%p>9tA@h004+uEb5 Date: Fri, 1 Jan 2021 13:57:13 +0300 Subject: [PATCH 58/83] Update Customizing-Application-Modules-Guide.md --- docs/en/Customizing-Application-Modules-Guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/Customizing-Application-Modules-Guide.md b/docs/en/Customizing-Application-Modules-Guide.md index 3f8597bc71..774cc83366 100644 --- a/docs/en/Customizing-Application-Modules-Guide.md +++ b/docs/en/Customizing-Application-Modules-Guide.md @@ -51,7 +51,7 @@ This section suggests some approaches if you decided to use pre-built applicatio ### Module Entity Extension System -Module entity extension system is the **main and high level extension system** that allows you to **define new properties** for existing entities of the depended modules. It automatically **adds properties to the entity, database, HTTP API and the user interface** in a single point. +> Module entity extension system is the **main and high level extension system** that allows you to **define new properties** for existing entities of the depended modules. It automatically **adds properties to the entity, database, HTTP API and the user interface** in a single point. See the [Module Entity Extensions document](Module-Entity-Extensions.md) to learn how to use it. @@ -66,7 +66,7 @@ In addition to the extensibility systems, you can partially or completely overri * [Overriding Services](Customizing-Application-Modules-Overriding-Services.md) * [Overriding the User Interface](Customizing-Application-Modules-Overriding-User-Interface.md) -### Additional UI Extensibility Systems +### Additional UI Extensibility Points There are some low level systems that you can control entity actions, table columns and page toolbar of a page defined by a module. From 246c2f37fe326279d40832dcabd8b62c35f1dccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 1 Jan 2021 14:02:01 +0300 Subject: [PATCH 59/83] Update Customizing-Application-Modules-Guide.md --- docs/en/Customizing-Application-Modules-Guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Customizing-Application-Modules-Guide.md b/docs/en/Customizing-Application-Modules-Guide.md index 774cc83366..56b94ae4fc 100644 --- a/docs/en/Customizing-Application-Modules-Guide.md +++ b/docs/en/Customizing-Application-Modules-Guide.md @@ -84,7 +84,7 @@ Data table column extension system allows you to add a new column in the data ta * [Data Table Column Extensions for ASP.NET Core UI](UI/AspNetCore/Data-Table-Column-Extensions.md) * [Data Table Column Extensions for Angular](UI/Angular/Data-Table-Column-Extensions.md) -#### Page Toolbar (TODO) +#### Page Toolbar Page toolbar system allows you to add components to the toolbar of a page; From 3a0569645c1de645c38ab2612e5492782f8bcc4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 1 Jan 2021 14:05:40 +0300 Subject: [PATCH 60/83] Update docs-nav.json --- docs/en/docs-nav.json | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index edfebc9544..217467e666 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -353,22 +353,8 @@ "path": "PlugIn-Modules.md" }, { - "text": "Customizing the Application Modules", - "path": "Customizing-Application-Modules-Guide.md", - "items": [ - { - "text": "Extending Entities", - "path": "Customizing-Application-Modules-Extending-Entities.md" - }, - { - "text": "Overriding Services", - "path": "Customizing-Application-Modules-Overriding-Services.md" - }, - { - "text": "Overriding the User Interface", - "path": "Customizing-Application-Modules-Overriding-User-Interface.md" - } - ] + "text": "Customizing/Extending Modules", + "path": "Customizing-Application-Modules-Guide.md" }, { "text": "Best Practices", From b4281ec1de5ff8e790ce5e6d41231c779421e9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 1 Jan 2021 17:48:39 +0300 Subject: [PATCH 61/83] Create Page-Progress.md --- docs/en/UI/Blazor/Page-Progress.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/en/UI/Blazor/Page-Progress.md diff --git a/docs/en/UI/Blazor/Page-Progress.md b/docs/en/UI/Blazor/Page-Progress.md new file mode 100644 index 0000000000..149c35293e --- /dev/null +++ b/docs/en/UI/Blazor/Page-Progress.md @@ -0,0 +1,3 @@ +# Blazor UI: Page Progress + +TODO \ No newline at end of file From 89523eac21790ef85a58b0ed6c36d68d0e0c30c8 Mon Sep 17 00:00:00 2001 From: GameBelial <243387971@qq.com> Date: Fri, 1 Jan 2021 23:34:28 +0800 Subject: [PATCH 62/83] Update the connection string information in the documentation and docker compose. --- docs/en/CLI.md | 2 +- docs/en/Entity-Framework-Core-Migrations.md | 10 +++++----- docs/en/Modules/Docs.md | 2 +- docs/en/Samples/Microservice-Demo.md | 6 +++--- docs/zh-Hans/CLI.md | 2 +- docs/zh-Hans/Entity-Framework-Core-Migrations.md | 10 +++++----- docs/zh-Hans/Modules/Docs.md | 2 +- docs/zh-Hans/Samples/Microservice-Demo.md | 6 +++--- .../appsettings.json | 2 +- .../appsettings.json | 2 +- .../ConsoleAppConsoleAppModule.cs | 2 +- .../appsettings.json | 2 +- .../app/Volo.BloggingTestApp/appsettings.json | 2 +- modules/cms-kit/docker-compose.override.yml | 14 +++++++------- .../host/Volo.CmsKit.HttpApi.Host/appsettings.json | 4 ++-- .../Volo.CmsKit.IdentityServer/appsettings.json | 2 +- .../host/Volo.CmsKit.Web.Unified/appsettings.json | 2 +- .../docs/app/VoloDocs.Migrator/appsettings.json | 2 +- modules/docs/app/VoloDocs.Web/appsettings.json | 2 +- modules/docs/docker-compose.migrate.yml | 2 +- modules/docs/docker-compose.override.yml | 2 +- .../module/aspnet-core/docker-compose.override.yml | 14 +++++++------- .../AbpPerfTest.WithAbp/appsettings.json | 2 +- .../AbpPerfTest.WithoutAbp/appsettings.json | 2 +- 24 files changed, 49 insertions(+), 49 deletions(-) diff --git a/docs/en/CLI.md b/docs/en/CLI.md index daf86025c4..a25b94aca0 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -105,7 +105,7 @@ abp new Acme.BookStore * `--preview`: Use latest preview version. * `--template-source` or `-ts`: Specifies a custom template source to use to build the project. Local and network sources can be used(Like `D:\local-template` or `https://.../my-template-file.zip`). * `--create-solution-folder` or `-csf`: Specifies if the project will be in a new folder in the output folder or directly the output folder. -* `--connection-string` or `-cs`: Overwrites the default connection strings in all `appsettings.json` files. The default connection string is `Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true` for EF Core and it is configured to use the SQL Server. If you want to use the EF Core, but need to change the DBMS, you can change it as [described here](Entity-Framework-Core-Other-DBMS.md) (after creating the solution). +* `--connection-string` or `-cs`: Overwrites the default connection strings in all `appsettings.json` files. The default connection string is `Server=localhost;Database=MyProjectName;Trusted_Connection=True` for EF Core and it is configured to use the SQL Server. If you want to use the EF Core, but need to change the DBMS, you can change it as [described here](Entity-Framework-Core-Other-DBMS.md) (after creating the solution). * `--database-management-system` or `-dbms`: Sets the database management system. Default is **SQL Server**. Supported DBMS's: * `SqlServer` * `MySQL` diff --git a/docs/en/Entity-Framework-Core-Migrations.md b/docs/en/Entity-Framework-Core-Migrations.md index a93ee217da..be5968a9af 100644 --- a/docs/en/Entity-Framework-Core-Migrations.md +++ b/docs/en/Entity-Framework-Core-Migrations.md @@ -586,7 +586,7 @@ First step is to change the connection string section inside all the `appsetting ````json "ConnectionStrings": { - "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True" } ```` @@ -594,10 +594,10 @@ Change it as shown below: ````json "ConnectionStrings": { - "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true", - "AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true", - "AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true", - "AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True", + "AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True", + "AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True", + "AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True" } ```` diff --git a/docs/en/Modules/Docs.md b/docs/en/Modules/Docs.md index 5780b4b827..35478d9ce0 100644 --- a/docs/en/Modules/Docs.md +++ b/docs/en/Modules/Docs.md @@ -47,7 +47,7 @@ The database connection string is located in `appsettings.json` of your `Acme.My ```json { "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True" } } ``` diff --git a/docs/en/Samples/Microservice-Demo.md b/docs/en/Samples/Microservice-Demo.md index 492dfb203b..285c2b10a0 100644 --- a/docs/en/Samples/Microservice-Demo.md +++ b/docs/en/Samples/Microservice-Demo.md @@ -842,7 +842,7 @@ It has a dedicated MongoDB database (MsDemo_Blogging) to store blog and posts. I ````json "ConnectionStrings": { - "Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True;MultipleActiveResultSets=true", + "Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True", "Blogging": "mongodb://localhost/MsDemo_Blogging" } ```` @@ -968,8 +968,8 @@ There are two connection strings in the `appsettings.json` file: ````json "ConnectionStrings": { - "Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True;MultipleActiveResultSets=true", - "ProductManagement": "Server=localhost;Database=MsDemo_ProductManagement;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True", + "ProductManagement": "Server=localhost;Database=MsDemo_ProductManagement;Trusted_Connection=True" } ```` diff --git a/docs/zh-Hans/CLI.md b/docs/zh-Hans/CLI.md index 4c63dcd818..4a02b1c3c8 100644 --- a/docs/zh-Hans/CLI.md +++ b/docs/zh-Hans/CLI.md @@ -103,7 +103,7 @@ abp new Acme.BookStore * `--preview`: 使用最新的预览版本. * `--template-source` 或者 `-ts`: 指定自定义模板源用于生成项目,可以使用本地源和网络源(例如 `D:\local-templat` 或 `https://.../my-template-file.zip`). * `--create-solution-folder` 或者 `-csf`: 指定项目是在输出文件夹中的新文件夹中还是直接在输出文件夹中. -* `--connection-string` 或者 `-cs`: 重写所有 `appsettings.json` 文件的默认连接字符串. 默认连接字符串是 `Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true`. 默认的数据库提供程序是 `SQL Server`. 如果你使用EF Core但需要更改DBMS,可以按[这里所述](Entity-Framework-Core-Other-DBMS.md)进行更改(创建解决方案之后). +* `--connection-string` 或者 `-cs`: 重写所有 `appsettings.json` 文件的默认连接字符串. 默认连接字符串是 `Server=localhost;Database=MyProjectName;Trusted_Connection=True`. 默认的数据库提供程序是 `SQL Server`. 如果你使用EF Core但需要更改DBMS,可以按[这里所述](Entity-Framework-Core-Other-DBMS.md)进行更改(创建解决方案之后). * `--local-framework-ref --abp-path`: 使用对项目的本地引用,而不是替换为NuGet包引用. ### update diff --git a/docs/zh-Hans/Entity-Framework-Core-Migrations.md b/docs/zh-Hans/Entity-Framework-Core-Migrations.md index 266c0f46b0..8708516f76 100644 --- a/docs/zh-Hans/Entity-Framework-Core-Migrations.md +++ b/docs/zh-Hans/Entity-Framework-Core-Migrations.md @@ -588,7 +588,7 @@ public class IdentityRoleExtendingService : ITransientDependency ````json "ConnectionStrings": { - "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True" } ```` @@ -596,10 +596,10 @@ public class IdentityRoleExtendingService : ITransientDependency ````json "ConnectionStrings": { - "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true", - "AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true", - "AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true", - "AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True", + "AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True", + "AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True", + "AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True" } ```` diff --git a/docs/zh-Hans/Modules/Docs.md b/docs/zh-Hans/Modules/Docs.md index acc956be1b..1d09552e50 100644 --- a/docs/zh-Hans/Modules/Docs.md +++ b/docs/zh-Hans/Modules/Docs.md @@ -47,7 +47,7 @@ ABP框架的[文档](docs.abp.io)也是使用的此模块. ```json { "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True" } } ``` diff --git a/docs/zh-Hans/Samples/Microservice-Demo.md b/docs/zh-Hans/Samples/Microservice-Demo.md index 59fa98e057..ca8b90a03f 100644 --- a/docs/zh-Hans/Samples/Microservice-Demo.md +++ b/docs/zh-Hans/Samples/Microservice-Demo.md @@ -843,7 +843,7 @@ Swagger UI已配置,是此服务的默认页面. 如果你导航到URL`http://lo ````json "ConnectionStrings": { - "Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True;MultipleActiveResultSets=true", + "Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True", "Blogging": "mongodb://localhost/MsDemo_Blogging" } ```` @@ -969,8 +969,8 @@ public class ProductServiceMigrationDbContext : AbpDbContext(options => { - options.ConnectionStrings.Default = "Server=localhost;Database=BlobStoring_Host;Trusted_Connection=True;MultipleActiveResultSets=true"; + options.ConnectionStrings.Default = "Server=localhost;Database=BlobStoring_Host;Trusted_Connection=True"; }); context.Services.AddAbpDbContext(options => diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/appsettings.json b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/appsettings.json index 2e1ff4f771..13d94f70db 100644 --- a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/appsettings.json +++ b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/appsettings.json @@ -1,5 +1,5 @@ { "ConnectionStrings": { - "Default": "Server=localhost;Database=BlobStoring_Host;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=BlobStoring_Host;Trusted_Connection=True" } } diff --git a/modules/blogging/app/Volo.BloggingTestApp/appsettings.json b/modules/blogging/app/Volo.BloggingTestApp/appsettings.json index c85ffe9489..6d3d120f4e 100644 --- a/modules/blogging/app/Volo.BloggingTestApp/appsettings.json +++ b/modules/blogging/app/Volo.BloggingTestApp/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "SqlServer": "Server=localhost;Database=BloggingTestApp;Trusted_Connection=True;MultipleActiveResultSets=true", + "SqlServer": "Server=localhost;Database=BloggingTestApp;Trusted_Connection=True", "MongoDb": "mongodb://localhost:27017/BloggingTestApp" } } \ No newline at end of file diff --git a/modules/cms-kit/docker-compose.override.yml b/modules/cms-kit/docker-compose.override.yml index 94b9df0c22..4cef8f8414 100644 --- a/modules/cms-kit/docker-compose.override.yml +++ b/modules/cms-kit/docker-compose.override.yml @@ -11,19 +11,19 @@ services: identity-server: environment: - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionStrings__Default=Server=sqlserver;Database=CmsKit_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__SqlServerCache=Server=sqlserver;Database=CmsKit_Cache;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__Default=Server=sqlserver;Database=CmsKit_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__SqlServerCache=Server=sqlserver;Database=CmsKit_Cache;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false ports: - "51600:80" cms-kit: environment: - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionStrings__Default=Server=sqlserver;Database=CmsKit_ModuleDb;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__AbpSettingManagement=Server=sqlserver;Database=CmsKit_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__AbpPermissionManagement=Server=sqlserver;Database=CmsKit_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__AbpAuditLogging=Server=sqlserver;Database=CmsKit_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__SqlServerCache=Server=sqlserver;Database=CmsKit_Cache;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__Default=Server=sqlserver;Database=CmsKit_ModuleDb;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__AbpSettingManagement=Server=sqlserver;Database=CmsKit_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__AbpPermissionManagement=Server=sqlserver;Database=CmsKit_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__AbpAuditLogging=Server=sqlserver;Database=CmsKit_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__SqlServerCache=Server=sqlserver;Database=CmsKit_Cache;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false - AuthServer__Authority=http://identity-server ports: - "51601:80" \ No newline at end of file diff --git a/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/appsettings.json b/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/appsettings.json index 06b66fcede..7811df81cb 100644 --- a/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/appsettings.json +++ b/modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/appsettings.json @@ -3,8 +3,8 @@ "CorsOrigins": "https://*.CmsKit.com,http://localhost:4200" }, "ConnectionStrings": { - "Default": "Server=localhost;Database=CmsKit_Main;Trusted_Connection=True;MultipleActiveResultSets=true", - "CmsKit": "Server=localhost;Database=CmsKit_Module;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=CmsKit_Main;Trusted_Connection=True", + "CmsKit": "Server=localhost;Database=CmsKit_Module;Trusted_Connection=True" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/appsettings.json b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/appsettings.json index e0f3118a11..f79959a2e0 100644 --- a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/appsettings.json +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/appsettings.json @@ -5,7 +5,7 @@ }, "AppSelfUrl": "https://localhost:44318/", "ConnectionStrings": { - "Default": "Server=localhost;Database=CmsKit_Main;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=CmsKit_Main;Trusted_Connection=True" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/appsettings.json b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/appsettings.json index 9b7fd1fa18..417b64b609 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/appsettings.json +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/appsettings.json @@ -1,5 +1,5 @@ { "ConnectionStrings": { - "Default": "Server=localhost;Database=CmsKit_Unified;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=localhost;Database=CmsKit_Unified;Trusted_Connection=True" } } diff --git a/modules/docs/app/VoloDocs.Migrator/appsettings.json b/modules/docs/app/VoloDocs.Migrator/appsettings.json index c9934c1e75..8ba3526f59 100644 --- a/modules/docs/app/VoloDocs.Migrator/appsettings.json +++ b/modules/docs/app/VoloDocs.Migrator/appsettings.json @@ -1,3 +1,3 @@ { - "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True;MultipleActiveResultSets=true" + "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True" } \ No newline at end of file diff --git a/modules/docs/app/VoloDocs.Web/appsettings.json b/modules/docs/app/VoloDocs.Web/appsettings.json index 8eea6b57cd..b1fb4d82bc 100644 --- a/modules/docs/app/VoloDocs.Web/appsettings.json +++ b/modules/docs/app/VoloDocs.Web/appsettings.json @@ -1,5 +1,5 @@ { - "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True;MultipleActiveResultSets=true", + "ConnectionString": "Server=localhost;Database=VoloDocs;Trusted_Connection=True", "LogoUrl": "/assets/images/Logo.png", "ElasticSearch": { "Url": "http://localhost:9200" diff --git a/modules/docs/docker-compose.migrate.yml b/modules/docs/docker-compose.migrate.yml index e88580debd..70142e4ce5 100644 --- a/modules/docs/docker-compose.migrate.yml +++ b/modules/docs/docker-compose.migrate.yml @@ -7,6 +7,6 @@ services: context: ../../ dockerfile: modules/docs/app/VoloDocs.Migrator/Dockerfile environment: - - ConnectionString=Server=sqlserver;Database=VoloDocs;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionString=Server=sqlserver;Database=VoloDocs;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false depends_on: - sqlserver diff --git a/modules/docs/docker-compose.override.yml b/modules/docs/docker-compose.override.yml index 6a8568ce6e..33508c10fe 100644 --- a/modules/docs/docker-compose.override.yml +++ b/modules/docs/docker-compose.override.yml @@ -10,7 +10,7 @@ services: volo-docs: environment: - - ConnectionString=Server=sqlserver;Database=VoloDocs;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionString=Server=sqlserver;Database=VoloDocs;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false - Title=VoloDocs - LogoUrl=/assets/images/Logo.png ports: diff --git a/templates/module/aspnet-core/docker-compose.override.yml b/templates/module/aspnet-core/docker-compose.override.yml index 8d583bacd7..061757bb76 100644 --- a/templates/module/aspnet-core/docker-compose.override.yml +++ b/templates/module/aspnet-core/docker-compose.override.yml @@ -11,19 +11,19 @@ services: identity-server: environment: - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionStrings__Default=Server=sqlserver;Database=MyProjectName_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__SqlServerCache=Server=sqlserver;Database=MyProjectName_Cache;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__Default=Server=sqlserver;Database=MyProjectName_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__SqlServerCache=Server=sqlserver;Database=MyProjectName_Cache;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false ports: - "51600:80" my-project-name: environment: - ASPNETCORE_URLS=http://0.0.0.0:80 - - ConnectionStrings__Default=Server=sqlserver;Database=MyProjectName_ModuleDb;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__AbpSettingManagement=Server=sqlserver;Database=MyProjectName_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__AbpPermissionManagement=Server=sqlserver;Database=MyProjectName_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__AbpAuditLogging=Server=sqlserver;Database=MyProjectName_Identity;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false - - ConnectionStrings__SqlServerCache=Server=sqlserver;Database=MyProjectName_Cache;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__Default=Server=sqlserver;Database=MyProjectName_ModuleDb;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__AbpSettingManagement=Server=sqlserver;Database=MyProjectName_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__AbpPermissionManagement=Server=sqlserver;Database=MyProjectName_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__AbpAuditLogging=Server=sqlserver;Database=MyProjectName_Identity;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false + - ConnectionStrings__SqlServerCache=Server=sqlserver;Database=MyProjectName_Cache;Trusted_Connection=True;User=sa;Password=yourStrong(!)Password;Integrated Security=false - AuthServer__Authority=http://identity-server ports: - "51601:80" \ No newline at end of file diff --git a/test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json b/test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json index 9cd22c72c3..b61498b126 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json +++ b/test/AbpPerfTest/AbpPerfTest.WithAbp/appsettings.json @@ -8,6 +8,6 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=AbpPerfTest_WithAbp;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=AbpPerfTest_WithAbp;Trusted_Connection=True" } } diff --git a/test/AbpPerfTest/AbpPerfTest.WithoutAbp/appsettings.json b/test/AbpPerfTest/AbpPerfTest.WithoutAbp/appsettings.json index 7f6ca466b2..0a5a9029ec 100644 --- a/test/AbpPerfTest/AbpPerfTest.WithoutAbp/appsettings.json +++ b/test/AbpPerfTest/AbpPerfTest.WithoutAbp/appsettings.json @@ -8,6 +8,6 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=AbpPerfTest_WithoutAbp;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=AbpPerfTest_WithoutAbp;Trusted_Connection=True" } } From af45dae2bef4a9abfb4af803b67884cdd5e71fd5 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 2 Jan 2021 20:44:49 +0300 Subject: [PATCH 63/83] add and expose default validation blueprints --- .../theme-shared/src/lib/constants/validation.ts | 16 ++++++++++++++++ .../packages/theme-shared/src/public-api.ts | 1 + 2 files changed, 17 insertions(+) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/constants/validation.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/constants/validation.ts b/npm/ng-packs/packages/theme-shared/src/lib/constants/validation.ts new file mode 100644 index 0000000000..463a7b01dc --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/constants/validation.ts @@ -0,0 +1,16 @@ +export const DEFAULT_VALIDATION_BLUEPRINTS = { + creditCard: 'AbpValidation::ThisFieldIsNotAValidCreditCardNumber.', + email: 'AbpValidation::ThisFieldIsNotAValidEmailAddress.', + invalid: 'AbpValidation::ThisFieldIsNotValid.', + max: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]', + maxlength: + 'AbpValidation::ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}[{{ requiredLength }}]', + min: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]', + minlength: + 'AbpValidation::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}[{{ requiredLength }}]', + ngbDate: 'AbpValidation::ThisFieldIsNotValid.', + passwordMismatch: 'AbpIdentity::Volo.Abp.Identity:PasswordConfirmationFailed', + range: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]', + required: 'AbpValidation::ThisFieldIsRequired.', + url: 'AbpValidation::ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl', +}; diff --git a/npm/ng-packs/packages/theme-shared/src/public-api.ts b/npm/ng-packs/packages/theme-shared/src/public-api.ts index 7cc8e821d5..5a4f9efe95 100644 --- a/npm/ng-packs/packages/theme-shared/src/public-api.ts +++ b/npm/ng-packs/packages/theme-shared/src/public-api.ts @@ -5,6 +5,7 @@ export * from './lib/animations'; export * from './lib/components'; export { BOOTSTRAP } from './lib/constants/styles'; +export * from './lib/constants/validation'; export * from './lib/directives'; export * from './lib/enums'; export { ErrorHandler } from './lib/handlers'; From ca5e3a36b43abcc7b356f802c84ec5fb98ce0ec7 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 2 Jan 2021 20:46:31 +0300 Subject: [PATCH 64/83] provide validation tokens in forRoot of theme shared --- .../theme-shared/src/lib/models/common.ts | 2 ++ .../src/lib/theme-shared.module.ts | 30 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts index 09171179c4..64047e0db7 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts @@ -1,7 +1,9 @@ import { Type } from '@angular/core'; +import { Validation } from '@ngx-validate/core'; export interface RootParams { httpErrorConfig: HttpErrorConfig; + validation?: Partial; } export type ErrorScreenErrorCodes = 401 | 403 | 404 | 500; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts index 6775c15e5a..037faee882 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts @@ -2,7 +2,13 @@ import { CoreModule, noop } from '@abp/ng.core'; import { DatePipe } from '@angular/common'; import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core'; import { NgbDateParserFormatter, NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap'; -import { NgxValidateCoreModule } from '@ngx-validate/core'; +import { + defaultMapErrorsFn, + NgxValidateCoreModule, + VALIDATION_BLUEPRINTS, + VALIDATION_MAP_ERRORS_FN, + VALIDATION_VALIDATE_ON_SUBMIT, +} from '@ngx-validate/core'; import { NgxDatatableModule } from '@swimlane/ngx-datatable'; import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component'; import { ButtonComponent } from './components/button/button.component'; @@ -18,6 +24,7 @@ import { TableEmptyMessageComponent } from './components/table-empty-message/tab import { TableComponent } from './components/table/table.component'; import { ToastContainerComponent } from './components/toast-container/toast-container.component'; import { ToastComponent } from './components/toast/toast.component'; +import { DEFAULT_VALIDATION_BLUEPRINTS } from './constants/validation'; import { LoadingDirective } from './directives/loading.directive'; import { NgxDatatableDefaultDirective } from './directives/ngx-datatable-default.directive'; import { NgxDatatableListDirective } from './directives/ngx-datatable-list.directive'; @@ -69,7 +76,9 @@ export class BaseThemeSharedModule {} exports: [BaseThemeSharedModule], }) export class ThemeSharedModule { - static forRoot(options = {} as RootParams): ModuleWithProviders { + static forRoot( + { httpErrorConfig, validation = {} } = {} as RootParams, + ): ModuleWithProviders { return { ngModule: ThemeSharedModule, providers: [ @@ -92,13 +101,28 @@ export class ThemeSharedModule { deps: [Injector], useFactory: initLazyStyleHandler, }, - { provide: HTTP_ERROR_CONFIG, useValue: options.httpErrorConfig }, + { provide: HTTP_ERROR_CONFIG, useValue: httpErrorConfig }, { provide: 'HTTP_ERROR_CONFIG', useFactory: httpErrorConfigFactory, deps: [HTTP_ERROR_CONFIG], }, { provide: NgbDateParserFormatter, useClass: DateParserFormatter }, + { + provide: VALIDATION_BLUEPRINTS, + useValue: { + ...DEFAULT_VALIDATION_BLUEPRINTS, + ...(validation.blueprints || {}), + }, + }, + { + provide: VALIDATION_MAP_ERRORS_FN, + useValue: validation.mapErrorsFn || defaultMapErrorsFn, + }, + { + provide: VALIDATION_VALIDATE_ON_SUBMIT, + useValue: validation.validateOnSubmit, + }, ], }; } From c28f0e65f1228515aa8174c9b7307c046892693b Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 2 Jan 2021 20:47:09 +0300 Subject: [PATCH 65/83] replace RootThemeBasicModule with individual tokens --- .../theme-basic/src/lib/theme-basic.module.ts | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts index a947809623..ee43ea2d6c 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts @@ -2,18 +2,22 @@ import { CoreModule } from '@abp/ng.core'; import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { ModuleWithProviders, NgModule } from '@angular/core'; import { NgbCollapseModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; -import { NgxValidateCoreModule } from '@ngx-validate/core'; +import { + NgxValidateCoreModule, + VALIDATION_ERROR_TEMPLATE, + VALIDATION_TARGET_SELECTOR, +} from '@ngx-validate/core'; import { AccountLayoutComponent } from './components/account-layout/account-layout.component'; import { ApplicationLayoutComponent } from './components/application-layout/application-layout.component'; import { EmptyLayoutComponent } from './components/empty-layout/empty-layout.component'; import { LogoComponent } from './components/logo/logo.component'; +import { CurrentUserComponent } from './components/nav-items/current-user.component'; +import { LanguagesComponent } from './components/nav-items/languages.component'; import { NavItemsComponent } from './components/nav-items/nav-items.component'; import { RoutesComponent } from './components/routes/routes.component'; import { ValidationErrorComponent } from './components/validation-error/validation-error.component'; -import { CurrentUserComponent } from './components/nav-items/current-user.component'; -import { LanguagesComponent } from './components/nav-items/languages.component'; -import { BASIC_THEME_STYLES_PROVIDERS } from './providers/styles.provider'; import { BASIC_THEME_NAV_ITEM_PROVIDERS } from './providers/nav-item.provider'; +import { BASIC_THEME_STYLES_PROVIDERS } from './providers/styles.provider'; export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent]; @@ -48,34 +52,19 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt export class ThemeBasicModule { static forRoot(): ModuleWithProviders { return { - ngModule: RootThemeBasicModule, - providers: [BASIC_THEME_NAV_ITEM_PROVIDERS, BASIC_THEME_STYLES_PROVIDERS], + ngModule: ThemeBasicModule, + providers: [ + BASIC_THEME_NAV_ITEM_PROVIDERS, + BASIC_THEME_STYLES_PROVIDERS, + { + provide: VALIDATION_ERROR_TEMPLATE, + useValue: ValidationErrorComponent, + }, + { + provide: VALIDATION_TARGET_SELECTOR, + useValue: '.form-group', + }, + ], }; } } - -@NgModule({ - imports: [ - NgxValidateCoreModule.forRoot({ - targetSelector: '.form-group', - blueprints: { - creditCard: 'AbpValidation::ThisFieldIsNotAValidCreditCardNumber.', - email: 'AbpValidation::ThisFieldIsNotAValidEmailAddress.', - invalid: 'AbpValidation::ThisFieldIsNotValid.', - max: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]', - maxlength: - 'AbpValidation::ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}[{{ requiredLength }}]', - min: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]', - minlength: - 'AbpValidation::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}[{{ requiredLength }}]', - ngbDate: 'AbpValidation::ThisFieldIsNotValid.', - passwordMismatch: 'AbpIdentity::Volo.Abp.Identity:PasswordConfirmationFailed', - range: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]', - required: 'AbpValidation::ThisFieldIsRequired.', - url: 'AbpValidation::ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl', - }, - errorTemplate: ValidationErrorComponent, - }), - ], -}) -export class RootThemeBasicModule {} From e869ac11dfbfc2f2f51127fbc772fd5487a751bb Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 2 Jan 2021 21:05:12 +0300 Subject: [PATCH 66/83] add config interface to theme shared testing module --- .../packages/theme-shared/testing/src/lib/models/config.ts | 5 +++++ .../packages/theme-shared/testing/src/lib/models/index.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 npm/ng-packs/packages/theme-shared/testing/src/lib/models/config.ts create mode 100644 npm/ng-packs/packages/theme-shared/testing/src/lib/models/index.ts diff --git a/npm/ng-packs/packages/theme-shared/testing/src/lib/models/config.ts b/npm/ng-packs/packages/theme-shared/testing/src/lib/models/config.ts new file mode 100644 index 0000000000..1b4825cf9f --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/testing/src/lib/models/config.ts @@ -0,0 +1,5 @@ +import { Validation } from '@ngx-validate/core'; + +export interface Config { + validation?: Partial; +} diff --git a/npm/ng-packs/packages/theme-shared/testing/src/lib/models/index.ts b/npm/ng-packs/packages/theme-shared/testing/src/lib/models/index.ts new file mode 100644 index 0000000000..f03c2281a9 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/testing/src/lib/models/index.ts @@ -0,0 +1 @@ +export * from './config'; From 1fbd9e82098459a03f9ead0bc9173ab72937c467 Mon Sep 17 00:00:00 2001 From: AnthonyHuang Date: Sat, 2 Jan 2021 12:23:49 -0700 Subject: [PATCH 67/83] Update Background-Workers.md --- docs/en/Background-Workers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/Background-Workers.md b/docs/en/Background-Workers.md index 2e1b9d2a90..8225aac2a6 100644 --- a/docs/en/Background-Workers.md +++ b/docs/en/Background-Workers.md @@ -80,7 +80,7 @@ public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase ## Register Background Worker -After creating a background worker class, you should to add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class: +After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class: ````csharp [DependsOn(typeof(AbpBackgroundWorkersModule))] @@ -137,4 +137,4 @@ ABP Framework's background worker system is good to implement periodic tasks. Ho ## See Also * [Quartz Integration for the background workers](Background-Workers-Quartz.md) -* [Background Jobs](Background-Jobs.md) \ No newline at end of file +* [Background Jobs](Background-Jobs.md) From b5310817db2607ffb214277a7f25b8a591afbbd1 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 2 Jan 2021 22:55:44 +0300 Subject: [PATCH 68/83] expose theme shared testing config interface --- npm/ng-packs/packages/theme-shared/testing/src/public-api.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npm/ng-packs/packages/theme-shared/testing/src/public-api.ts b/npm/ng-packs/packages/theme-shared/testing/src/public-api.ts index 14355a8a28..dc639b1462 100644 --- a/npm/ng-packs/packages/theme-shared/testing/src/public-api.ts +++ b/npm/ng-packs/packages/theme-shared/testing/src/public-api.ts @@ -1 +1,3 @@ +import * as ThemeSharedTesting from './lib/models'; export * from './lib/theme-shared-testing.module'; +export { ThemeSharedTesting }; From efad3b7b2e6f58f8b1cafff0c475d964cdedef86 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 2 Jan 2021 22:56:54 +0300 Subject: [PATCH 69/83] pass validation options to theme shared testing --- .../src/lib/theme-shared-testing.module.ts | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/theme-shared/testing/src/lib/theme-shared-testing.module.ts b/npm/ng-packs/packages/theme-shared/testing/src/lib/theme-shared-testing.module.ts index 323281046a..52abb12ffe 100644 --- a/npm/ng-packs/packages/theme-shared/testing/src/lib/theme-shared-testing.module.ts +++ b/npm/ng-packs/packages/theme-shared/testing/src/lib/theme-shared-testing.module.ts @@ -1,11 +1,19 @@ import { BaseThemeSharedModule, DateParserFormatter, + DEFAULT_VALIDATION_BLUEPRINTS, THEME_SHARED_ROUTE_PROVIDERS, } from '@abp/ng.theme.shared'; import { ModuleWithProviders, NgModule } from '@angular/core'; import { RouterTestingModule } from '@angular/router/testing'; import { NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap'; +import { + defaultMapErrorsFn, + VALIDATION_BLUEPRINTS, + VALIDATION_MAP_ERRORS_FN, + VALIDATION_VALIDATE_ON_SUBMIT, +} from '@ngx-validate/core'; +import { Config } from './models/config'; /** * ThemeSharedTestingModule is the module that will be used in tests @@ -15,12 +23,29 @@ import { NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap'; imports: [RouterTestingModule, BaseThemeSharedModule], }) export class ThemeSharedTestingModule { - static withConfig(): ModuleWithProviders { + static withConfig( + { validation = {} } = {} as Config, + ): ModuleWithProviders { return { ngModule: ThemeSharedTestingModule, providers: [ THEME_SHARED_ROUTE_PROVIDERS, { provide: NgbDateParserFormatter, useClass: DateParserFormatter }, + { + provide: VALIDATION_BLUEPRINTS, + useValue: { + ...DEFAULT_VALIDATION_BLUEPRINTS, + ...(validation.blueprints || {}), + }, + }, + { + provide: VALIDATION_MAP_ERRORS_FN, + useValue: validation.mapErrorsFn || defaultMapErrorsFn, + }, + { + provide: VALIDATION_VALIDATE_ON_SUBMIT, + useValue: validation.validateOnSubmit, + }, ], }; } From 2bf98ea68b0497474871136a56f30039cc03036d Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 2 Jan 2021 23:23:14 +0300 Subject: [PATCH 70/83] add a BaseThemeBasicModule --- .../packages/theme-basic/src/lib/theme-basic.module.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts index ee43ea2d6c..be08f78e5b 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts @@ -49,6 +49,12 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt ], entryComponents: [...LAYOUTS, ValidationErrorComponent, CurrentUserComponent, LanguagesComponent], }) +export class BaseThemeBasicModule {} + +@NgModule({ + exports: [BaseThemeBasicModule], + imports: [BaseThemeBasicModule], +}) export class ThemeBasicModule { static forRoot(): ModuleWithProviders { return { From f3d919b7d8f1683a80366e9f8d4f78f08664d974 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sat, 2 Jan 2021 23:23:55 +0300 Subject: [PATCH 71/83] add theme basic testing module and its entry point --- .../theme-basic/testing/ng-package.json | 7 ++++ .../src/lib/theme-basic-testing.module.ts | 32 +++++++++++++++++++ .../theme-basic/testing/src/public-api.ts | 1 + 3 files changed, 40 insertions(+) create mode 100644 npm/ng-packs/packages/theme-basic/testing/ng-package.json create mode 100644 npm/ng-packs/packages/theme-basic/testing/src/lib/theme-basic-testing.module.ts create mode 100644 npm/ng-packs/packages/theme-basic/testing/src/public-api.ts diff --git a/npm/ng-packs/packages/theme-basic/testing/ng-package.json b/npm/ng-packs/packages/theme-basic/testing/ng-package.json new file mode 100644 index 0000000000..c539597da7 --- /dev/null +++ b/npm/ng-packs/packages/theme-basic/testing/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/theme-basic/testing", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/npm/ng-packs/packages/theme-basic/testing/src/lib/theme-basic-testing.module.ts b/npm/ng-packs/packages/theme-basic/testing/src/lib/theme-basic-testing.module.ts new file mode 100644 index 0000000000..7df6d40231 --- /dev/null +++ b/npm/ng-packs/packages/theme-basic/testing/src/lib/theme-basic-testing.module.ts @@ -0,0 +1,32 @@ +import { + BaseThemeBasicModule, + BASIC_THEME_NAV_ITEM_PROVIDERS, + BASIC_THEME_STYLES_PROVIDERS, + ValidationErrorComponent, +} from '@abp/ng.theme.basic'; +import { ModuleWithProviders, NgModule } from '@angular/core'; +import { VALIDATION_ERROR_TEMPLATE, VALIDATION_TARGET_SELECTOR } from '@ngx-validate/core'; + +@NgModule({ + exports: [BaseThemeBasicModule], + imports: [BaseThemeBasicModule], +}) +export class ThemeBasicTestingModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: ThemeBasicTestingModule, + providers: [ + BASIC_THEME_NAV_ITEM_PROVIDERS, + BASIC_THEME_STYLES_PROVIDERS, + { + provide: VALIDATION_ERROR_TEMPLATE, + useValue: ValidationErrorComponent, + }, + { + provide: VALIDATION_TARGET_SELECTOR, + useValue: '.form-group', + }, + ], + }; + } +} diff --git a/npm/ng-packs/packages/theme-basic/testing/src/public-api.ts b/npm/ng-packs/packages/theme-basic/testing/src/public-api.ts new file mode 100644 index 0000000000..24a3ac7586 --- /dev/null +++ b/npm/ng-packs/packages/theme-basic/testing/src/public-api.ts @@ -0,0 +1 @@ +export * from './lib/theme-basic-testing.module'; From 3208ec57844d7f37ce78d746201d1336277b579e Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Sun, 3 Jan 2021 13:27:17 +0300 Subject: [PATCH 72/83] update blueprint extension in validation document --- docs/en/UI/Angular/Form-Validation.md | 66 +++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/docs/en/UI/Angular/Form-Validation.md b/docs/en/UI/Angular/Form-Validation.md index 38e7969eea..a178fa213c 100644 --- a/docs/en/UI/Angular/Form-Validation.md +++ b/docs/en/UI/Angular/Form-Validation.md @@ -6,23 +6,52 @@ Reactive forms in ABP Angular UI are validated by [ngx-validate](https://www.npm ## How to Add New Error Messages -You can add a new error message by providing the `VALIDATION_BLUEPRINTS` injection token from your root module. +You can add a new error message by passing validation options to the `ThemeSharedModule` in your root module. ```js import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core"; +import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared"; @NgModule({ + imports: [ + ThemeSharedModule.forRoot({ + validation: { + blueprints: { + uniqueUsername: "::AlreadyExists[{%{{{ username }}}%}]", + }, + }, + + // rest of theme shared config + }), + + // other imports + ], + // rest of the module metadata +}) +export class AppModule {} +``` + +Alternatively, you may provide the `VALIDATION_BLUEPRINTS` token directly in your root module. Please do not forget to spread `DEFAULT_VALIDATION_BLUEPRINTS`. Otherwise, built-in ABP validation messages will not work. +```js +import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core"; +import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared"; + +@NgModule({ providers: [ - // other providers { provide: VALIDATION_BLUEPRINTS, useValue: { + ...DEFAULT_VALIDATION_BLUEPRINTS, uniqueUsername: "::AlreadyExists[{%{{{ username }}}%}]", }, }, + + // other providers ], + + // rest of the module metadata }) export class AppModule {} ``` @@ -40,7 +69,7 @@ In this example; ## How to Change Existing Error Messages -You can overwrite an existing error message by providing `VALIDATION_BLUEPRINTS` injection token from your root module. Let's imagine you have a custom localization resource for required inputs. +You can overwrite an existing error message by passing validation options to the `ThemeSharedModule` in your root module. Let's imagine you have a custom localization resource for required inputs. ```json "RequiredInput": "Oops! We need this input." @@ -50,19 +79,48 @@ To use this instead of the built-in required input message, all you need to do i ```js import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core"; +import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared"; @NgModule({ + imports: [ + ThemeSharedModule.forRoot({ + validation: { + blueprints: { + required: "::RequiredInput", + }, + }, + + // rest of theme shared config + }), + + // other imports + ], + // rest of the module metadata +}) +export class AppModule {} +``` + +Alternatively, you may provide the `VALIDATION_BLUEPRINTS` token directly in your root module. Please do not forget to spread `DEFAULT_VALIDATION_BLUEPRINTS`. Otherwise, built-in ABP validation messages will not work. +```js +import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core"; +import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared"; + +@NgModule({ providers: [ - // other providers { provide: VALIDATION_BLUEPRINTS, useValue: { + ...DEFAULT_VALIDATION_BLUEPRINTS, required: "::RequiredInput", }, }, + + // other providers ], + + // rest of the module metadata }) export class AppModule {} ``` From 6c0b543679746021e13212d9014894dfd3cb33cf Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 4 Jan 2021 11:10:37 +0800 Subject: [PATCH 73/83] Comment RoleDeletedEventHandler --- .../Identity/RoleDeletedEventHandler.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs index 806a37de7c..b3fd565b24 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs @@ -7,20 +7,20 @@ using Volo.Abp.Identity; namespace Volo.Abp.PermissionManagement.Identity { - public class RoleDeletedEventHandler : - ILocalEventHandler>, - ITransientDependency - { - protected IPermissionManager PermissionManager { get; } - - public RoleDeletedEventHandler(IPermissionManager permissionManager) - { - PermissionManager = permissionManager; - } - - public virtual async Task HandleEventAsync(EntityDeletedEventData eventData) - { - await PermissionManager.DeleteAsync(RolePermissionValueProvider.ProviderName, eventData.Entity.Name); - } - } + // public class RoleDeletedEventHandler : + // ILocalEventHandler>, + // ITransientDependency + // { + // protected IPermissionManager PermissionManager { get; } + // + // public RoleDeletedEventHandler(IPermissionManager permissionManager) + // { + // PermissionManager = permissionManager; + // } + // + // public virtual async Task HandleEventAsync(EntityDeletedEventData eventData) + // { + // await PermissionManager.DeleteAsync(RolePermissionValueProvider.ProviderName, eventData.Entity.Name); + // } + // } } From af2e3fc9df1270e786df885146c83e2a34e9888c Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 4 Jan 2021 11:16:47 +0800 Subject: [PATCH 74/83] Use async repository method in Blogging module. --- .../Blogging/Blogs/EfCoreBlogRepository.cs | 2 +- .../Comments/EfCoreCommentRepository.cs | 12 ++++++------ .../Blogging/Posts/EfCorePostRepository.cs | 18 +++++++++--------- .../Blogging/Tagging/EfCoreTagRepository.cs | 10 +++++----- .../Volo/Blogging/Blogs/MongoBlogRepository.cs | 2 +- .../Comments/MongoCommentRepository.cs | 8 ++++---- .../Volo/Blogging/Posts/MongoPostRepository.cs | 12 ++++++------ .../Blogging/Tagging/MongoTagRepository.cs | 10 +++++----- .../Blogging/Users/MongoBlogUserRepository.cs | 2 +- 9 files changed, 38 insertions(+), 38 deletions(-) diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Blogs/EfCoreBlogRepository.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Blogs/EfCoreBlogRepository.cs index 604f7ca8b5..564d45dc7a 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Blogs/EfCoreBlogRepository.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Blogs/EfCoreBlogRepository.cs @@ -17,7 +17,7 @@ namespace Volo.Blogging.Blogs public async Task FindByShortNameAsync(string shortName) { - return await DbSet.FirstOrDefaultAsync(p => p.ShortName == shortName); + return await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.ShortName == shortName); } } } diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Comments/EfCoreCommentRepository.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Comments/EfCoreCommentRepository.cs index 751d106071..6c28b521aa 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Comments/EfCoreCommentRepository.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Comments/EfCoreCommentRepository.cs @@ -11,14 +11,14 @@ namespace Volo.Blogging.Comments { public class EfCoreCommentRepository : EfCoreRepository, ICommentRepository { - public EfCoreCommentRepository(IDbContextProvider dbContextProvider) + public EfCoreCommentRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) { } public async Task> GetListOfPostAsync(Guid postId) { - return await DbSet + return await (await GetDbSetAsync()) .Where(a => a.PostId == postId) .OrderBy(a => a.CreationTime) .ToListAsync(); @@ -26,20 +26,20 @@ namespace Volo.Blogging.Comments public async Task GetCommentCountOfPostAsync(Guid postId) { - return await DbSet + return await (await GetDbSetAsync()) .CountAsync(a => a.PostId == postId); } public async Task> GetRepliesOfComment(Guid id) { - return await DbSet + return await (await GetDbSetAsync()) .Where(a => a.RepliedCommentId == id).ToListAsync(); } public async Task DeleteOfPost(Guid id) { - var recordsToDelete = DbSet.Where(pt => pt.PostId == id); - DbSet.RemoveRange(recordsToDelete); + var recordsToDelete = (await GetDbSetAsync()).Where(pt => pt.PostId == id); + (await GetDbSetAsync()).RemoveRange(recordsToDelete); } } } diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs index b152f3ae7d..a5a84fd340 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Posts/EfCorePostRepository.cs @@ -20,24 +20,24 @@ namespace Volo.Blogging.Posts public async Task> GetPostsByBlogId(Guid id) { - return await DbSet.Where(p => p.BlogId == id).OrderByDescending(p=>p.CreationTime).ToListAsync(); + return await (await GetDbSetAsync()).Where(p => p.BlogId == id).OrderByDescending(p=>p.CreationTime).ToListAsync(); } - public Task IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null) + public async Task IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null) { - var query = DbSet.Where(p => blogId == p.BlogId && p.Url == url); + var query = (await GetDbSetAsync()).Where(p => blogId == p.BlogId && p.Url == url); if (excludingPostId != null) { query = query.Where(p => excludingPostId != p.Id); } - return query.AnyAsync(); + return await query.AnyAsync(); } public async Task GetPostByUrl(Guid blogId, string url) { - var post = await DbSet.FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url); + var post = await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url); if (post == null) { @@ -51,18 +51,18 @@ namespace Volo.Blogging.Posts { if (!descending) { - return await DbSet.Where(x=>x.BlogId==blogId).OrderByDescending(x => x.CreationTime).ToListAsync(); + return await (await GetDbSetAsync()).Where(x=>x.BlogId==blogId).OrderByDescending(x => x.CreationTime).ToListAsync(); } else { - return await DbSet.Where(x => x.BlogId == blogId).OrderBy(x => x.CreationTime).ToListAsync(); + return await (await GetDbSetAsync()).Where(x => x.BlogId == blogId).OrderBy(x => x.CreationTime).ToListAsync(); } } - public override IQueryable WithDetails() + public override async Task> WithDetailsAsync() { - return GetQueryable().IncludeDetails(); + return (await GetQueryableAsync()).IncludeDetails(); } } } diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs index 3e897fa7e3..a92ae780da 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/Tagging/EfCoreTagRepository.cs @@ -19,27 +19,27 @@ namespace Volo.Blogging.Tagging public async Task> GetListAsync(Guid blogId) { - return await DbSet.Where(t=>t.BlogId == blogId).ToListAsync(); + return await (await GetDbSetAsync()).Where(t=>t.BlogId == blogId).ToListAsync(); } public async Task GetByNameAsync(Guid blogId, string name) { - return await DbSet.FirstAsync(t=> t.BlogId == blogId && t.Name == name); + return await (await GetDbSetAsync()).FirstAsync(t=> t.BlogId == blogId && t.Name == name); } public async Task FindByNameAsync(Guid blogId, string name) { - return await DbSet.FirstOrDefaultAsync(t => t.BlogId == blogId && t.Name == name); + return await (await GetDbSetAsync()).FirstOrDefaultAsync(t => t.BlogId == blogId && t.Name == name); } public async Task> GetListAsync(IEnumerable ids) { - return await DbSet.Where(t => ids.Contains(t.Id)).ToListAsync(); + return await (await GetDbSetAsync()).Where(t => ids.Contains(t.Id)).ToListAsync(); } public async Task DecreaseUsageCountOfTagsAsync(List ids, CancellationToken cancellationToken = default) { - var tags = await DbSet + var tags = await (await GetDbSetAsync()) .Where(t => ids.Any(id => id == t.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Blogs/MongoBlogRepository.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Blogs/MongoBlogRepository.cs index b1c7b5d319..6025dfe3ca 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Blogs/MongoBlogRepository.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Blogs/MongoBlogRepository.cs @@ -15,7 +15,7 @@ namespace Volo.Blogging.Blogs public async Task FindByShortNameAsync(string shortName) { - return await GetMongoQueryable().FirstOrDefaultAsync(p => p.ShortName == shortName); + return await (await GetMongoQueryableAsync()).FirstOrDefaultAsync(p => p.ShortName == shortName); } } } diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs index b17c7f906f..bbbe60345b 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Comments/MongoCommentRepository.cs @@ -17,7 +17,7 @@ namespace Volo.Blogging.Comments public async Task> GetListOfPostAsync(Guid postId) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync()) .Where(a => a.PostId == postId) .OrderBy(a => a.CreationTime) .ToListAsync(); @@ -25,19 +25,19 @@ namespace Volo.Blogging.Comments public async Task GetCommentCountOfPostAsync(Guid postId) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync()) .CountAsync(a => a.PostId == postId); } public async Task> GetRepliesOfComment(Guid id) { - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync()) .Where(a => a.RepliedCommentId == id).ToListAsync(); } public async Task DeleteOfPost(Guid id) { - var recordsToDelete = GetMongoQueryable().Where(pt => pt.PostId == id); + var recordsToDelete = (await GetMongoQueryableAsync()).Where(pt => pt.PostId == id); foreach (var record in recordsToDelete) { diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Posts/MongoPostRepository.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Posts/MongoPostRepository.cs index e12e5f29de..27f4ad4348 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Posts/MongoPostRepository.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Posts/MongoPostRepository.cs @@ -18,25 +18,25 @@ namespace Volo.Blogging.Posts public async Task> GetPostsByBlogId(Guid id) { - return await GetMongoQueryable().Where(p => p.BlogId == id).OrderByDescending(p => p.CreationTime).ToListAsync(); + return await (await GetMongoQueryableAsync()).Where(p => p.BlogId == id).OrderByDescending(p => p.CreationTime).ToListAsync(); } - public Task IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null) + public async Task IsPostUrlInUseAsync(Guid blogId, string url, Guid? excludingPostId = null) { - var query = GetMongoQueryable().Where(p => blogId == p.BlogId && p.Url == url); + var query = (await GetMongoQueryableAsync()).Where(p => blogId == p.BlogId && p.Url == url); if (excludingPostId != null) { query = query.Where(p => excludingPostId != p.Id); } - return query.AnyAsync(); + return await query.AnyAsync(); } public async Task GetPostByUrl(Guid blogId, string url) { - var post = await GetMongoQueryable().FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url); + var post = await (await GetMongoQueryableAsync()).FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url); if (post == null) { @@ -48,7 +48,7 @@ namespace Volo.Blogging.Posts public async Task> GetOrderedList(Guid blogId, bool @descending = false) { - var query = GetMongoQueryable().Where(x => x.BlogId == blogId); + var query = (await GetMongoQueryableAsync()).Where(x => x.BlogId == blogId); if (!descending) { diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs index 2c0b3b97bf..f0024b37d7 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Tagging/MongoTagRepository.cs @@ -20,27 +20,27 @@ namespace Volo.Blogging.Tagging public async Task> GetListAsync(Guid blogId) { - return await GetMongoQueryable().Where(t => t.BlogId == blogId).ToListAsync(); + return await (await GetMongoQueryableAsync()).Where(t => t.BlogId == blogId).ToListAsync(); } public async Task GetByNameAsync(Guid blogId, string name) { - return await GetMongoQueryable().Where(t => t.BlogId == blogId && t.Name == name).FirstAsync(); + return await (await GetMongoQueryableAsync()).Where(t => t.BlogId == blogId && t.Name == name).FirstAsync(); } public async Task FindByNameAsync(Guid blogId, string name) { - return await GetMongoQueryable().Where(t => t.BlogId == blogId && t.Name == name).FirstOrDefaultAsync(); + return await (await GetMongoQueryableAsync()).Where(t => t.BlogId == blogId && t.Name == name).FirstOrDefaultAsync(); } public async Task> GetListAsync(IEnumerable ids) { - return await GetMongoQueryable().Where(t => ids.Contains(t.Id)).ToListAsync(); + return await (await GetMongoQueryableAsync()).Where(t => ids.Contains(t.Id)).ToListAsync(); } public async Task DecreaseUsageCountOfTagsAsync(List ids, CancellationToken cancellationToken = default) { - var tags = await GetMongoQueryable() + var tags = await (await GetMongoQueryableAsync()) .Where(t => ids.Contains(t.Id)) .ToListAsync(GetCancellationToken(cancellationToken)); diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Users/MongoBlogUserRepository.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Users/MongoBlogUserRepository.cs index a0b7655946..fdcf4d0097 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Users/MongoBlogUserRepository.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/Users/MongoBlogUserRepository.cs @@ -17,7 +17,7 @@ namespace Volo.Blogging.Users public async Task> GetUsersAsync(int maxCount, string filter, CancellationToken cancellationToken) { - var query = GetMongoQueryable(); + var query = await GetMongoQueryableAsync(cancellationToken); if (!string.IsNullOrWhiteSpace(filter)) { From cb38a0fa7439d5e826d3fbedc4bb7405a572090e Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 4 Jan 2021 11:29:36 +0800 Subject: [PATCH 75/83] Use async repository method in CmsKit module. --- .../Volo/CmsKit/Comments/EfCoreCommentRepository.cs | 6 +++--- .../Volo/CmsKit/Pages/EfCorePageRepository.cs | 6 +++--- .../Volo/CmsKit/Ratings/EfCoreRatingRepository.cs | 6 +++--- .../CmsKit/Reactions/EfCoreUserReactionRepository.cs | 6 +++--- .../Volo/CmsKit/Tags/EfCoreTagRepository.cs | 8 ++++---- .../CmsKit/MongoDB/Comments/MongoCommentRepository.cs | 8 ++++---- .../Volo/CmsKit/MongoDB/Pages/MongoPageRepository.cs | 8 ++++---- .../CmsKit/MongoDB/Ratings/MongoRatingRepository.cs | 6 +++--- .../MongoDB/Reactions/MongoUserReactionRepository.cs | 6 +++--- .../Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs | 10 +++++----- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs index 9dec7877f8..40496aaef8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Comments/EfCoreCommentRepository.cs @@ -28,8 +28,8 @@ namespace Volo.CmsKit.Comments Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - var query = from comment in DbSet - join user in DbContext.Set() on comment.CreatorId equals user.Id + var query = from comment in (await GetDbSetAsync()) + join user in (await GetDbContextAsync()).Set() on comment.CreatorId equals user.Id where entityType == comment.EntityType && entityId == comment.EntityId orderby comment.CreationTime select new CommentWithAuthorQueryResultItem @@ -45,7 +45,7 @@ namespace Volo.CmsKit.Comments Comment comment, CancellationToken cancellationToken = default) { - var replies = await DbSet + var replies = await (await GetDbSetAsync()) .Where(x => x.RepliedCommentId == comment.Id) .ToListAsync(GetCancellationToken(cancellationToken)); diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Pages/EfCorePageRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Pages/EfCorePageRepository.cs index 4502a13b4c..93a7df00d2 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Pages/EfCorePageRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Pages/EfCorePageRepository.cs @@ -23,9 +23,9 @@ namespace Volo.CmsKit.Pages return FindAsync(x => x.Url == url); } - public Task DoesExistAsync(string url) + public async Task DoesExistAsync(string url) { - return DbSet.AnyAsync(x => x.Url == url); + return await (await GetDbSetAsync()).AnyAsync(x => x.Url == url); } } -} \ No newline at end of file +} diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Ratings/EfCoreRatingRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Ratings/EfCoreRatingRepository.cs index 810335b4d6..a48c288932 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Ratings/EfCoreRatingRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Ratings/EfCoreRatingRepository.cs @@ -24,7 +24,7 @@ namespace Volo.CmsKit.Ratings Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - var rating = await DbSet.FirstOrDefaultAsync( + var rating = await (await GetDbSetAsync()).FirstOrDefaultAsync( r => r.EntityType == entityType && r.EntityId == entityId && r.CreatorId == userId, GetCancellationToken(cancellationToken)); @@ -38,7 +38,7 @@ namespace Volo.CmsKit.Ratings Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); var query = ( - from rating in DbSet + from rating in (await GetDbSetAsync()) where rating.EntityType == entityType && rating.EntityId == entityId group rating by rating.StarCount into g @@ -54,4 +54,4 @@ namespace Volo.CmsKit.Ratings return ratings; } } -} \ No newline at end of file +} diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs index da89de4c74..65824c79b6 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Reactions/EfCoreUserReactionRepository.cs @@ -30,7 +30,7 @@ namespace Volo.CmsKit.Reactions Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(reactionName, nameof(reactionName)); - return await DbSet + return await (await GetDbSetAsync()) .Where(x => x.CreatorId == userId && x.EntityType == entityType && @@ -48,7 +48,7 @@ namespace Volo.CmsKit.Reactions Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - return await DbSet + return await (await GetDbSetAsync()) .Where(x => x.CreatorId == userId && x.EntityType == entityType && @@ -64,7 +64,7 @@ namespace Volo.CmsKit.Reactions Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - return await DbSet + return await (await GetDbSetAsync()) .Where(x => x.EntityType == entityType && x.EntityId == entityId) diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs index 0b6cfe1f48..3d917a059a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs @@ -19,13 +19,13 @@ namespace Volo.CmsKit.Tags { } - public virtual Task AnyAsync( + public virtual async Task AnyAsync( [NotNull] string entityType, [NotNull] string name, Guid? tenantId = null, CancellationToken cancellationToken = default) { - return DbSet.AnyAsync(x => + return await (await GetDbSetAsync()).AnyAsync(x => x.EntityType == entityType && x.Name == name && x.TenantId == tenantId, @@ -64,12 +64,12 @@ namespace Volo.CmsKit.Tags Guid? tenantId = null, CancellationToken cancellationToken = default) { - var entityTagIds = await DbContext.Set() + var entityTagIds = await (await GetDbContextAsync()).Set() .Where(q => q.EntityId == entityId && q.TenantId == tenantId) .Select(q => q.TagId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); - var query = DbSet + var query = (await GetDbSetAsync()) .Where(x => x.EntityType == entityType && x.TenantId == tenantId && entityTagIds.Contains(x.Id)); diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Comments/MongoCommentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Comments/MongoCommentRepository.cs index 9564bcf9f8..5d16c6d55c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Comments/MongoCommentRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Comments/MongoCommentRepository.cs @@ -26,15 +26,15 @@ namespace Volo.CmsKit.MongoDB.Comments Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - var authorsQuery = from comment in GetMongoQueryable() - join user in DbContext.CmsUsers on comment.CreatorId equals user.Id + var authorsQuery = from comment in (await GetMongoQueryableAsync(cancellationToken)) + join user in (await GetDbContextAsync(cancellationToken)).CmsUsers on comment.CreatorId equals user.Id where entityType == comment.EntityType && entityId == comment.EntityId orderby comment.CreationTime select user; var authors = await authorsQuery.ToListAsync(GetCancellationToken(cancellationToken)); - var comments = await GetMongoQueryable() + var comments = await (await GetMongoQueryableAsync(cancellationToken)) .Where(c => c.EntityId == entityId && c.EntityType == entityType) .OrderBy(c => c.CreationTime) .ToListAsync(GetCancellationToken(cancellationToken)); @@ -53,7 +53,7 @@ namespace Volo.CmsKit.MongoDB.Comments Comment comment, CancellationToken cancellationToken = default) { - var replies = await GetMongoQueryable() + var replies = await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.RepliedCommentId == comment.Id) .ToListAsync(GetCancellationToken(cancellationToken)); diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Pages/MongoPageRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Pages/MongoPageRepository.cs index e7c6cd32f5..8537500c96 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Pages/MongoPageRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Pages/MongoPageRepository.cs @@ -22,10 +22,10 @@ namespace Volo.CmsKit.MongoDB.Pages { return FindAsync(x => x.Url == url); } - - public Task DoesExistAsync(string url) + + public async Task DoesExistAsync(string url) { - return GetMongoQueryable().AnyAsync(x => x.Url == url); + return await (await GetMongoQueryableAsync()).AnyAsync(x => x.Url == url); } } -} \ No newline at end of file +} diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Ratings/MongoRatingRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Ratings/MongoRatingRepository.cs index 92f7f992da..8ff8b4f81d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Ratings/MongoRatingRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Ratings/MongoRatingRepository.cs @@ -25,7 +25,7 @@ namespace Volo.CmsKit.MongoDB.Ratings Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - var rating = await GetMongoQueryable() + var rating = await (await GetMongoQueryableAsync(cancellationToken)) .FirstOrDefaultAsync(r => r.EntityType == entityType && r.EntityId == entityId && r.CreatorId == userId, GetCancellationToken(cancellationToken)); @@ -39,7 +39,7 @@ namespace Volo.CmsKit.MongoDB.Ratings Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); var query = ( - from rating in GetMongoQueryable() + from rating in (await GetMongoQueryableAsync(cancellationToken)) where rating.EntityType == entityType && rating.EntityId == entityId group rating by rating.StarCount into g @@ -55,4 +55,4 @@ namespace Volo.CmsKit.MongoDB.Ratings return ratings; } } -} \ No newline at end of file +} diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Reactions/MongoUserReactionRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Reactions/MongoUserReactionRepository.cs index e3a09c4514..6ac4cf1b80 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Reactions/MongoUserReactionRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Reactions/MongoUserReactionRepository.cs @@ -29,7 +29,7 @@ namespace Volo.CmsKit.MongoDB.Reactions Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); Check.NotNullOrWhiteSpace(reactionName, nameof(reactionName)); - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.CreatorId == userId && x.EntityType == entityType && @@ -47,7 +47,7 @@ namespace Volo.CmsKit.MongoDB.Reactions Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.CreatorId == userId && x.EntityType == entityType && @@ -63,7 +63,7 @@ namespace Volo.CmsKit.MongoDB.Reactions Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - return await GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .Where(x => x.EntityType == entityType && x.EntityId == entityId) diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs index 86dc20d83c..02c42c22fb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs @@ -18,13 +18,13 @@ namespace Volo.CmsKit.MongoDB.Tags { } - public Task AnyAsync( + public async Task AnyAsync( [NotNull] string entityType, [NotNull] string name, Guid? tenantId = null, CancellationToken cancellationToken = default) { - return GetMongoQueryable() + return await (await GetMongoQueryableAsync(cancellationToken)) .AnyAsync(x => x.EntityType == entityType && x.Name == name && @@ -64,13 +64,13 @@ namespace Volo.CmsKit.MongoDB.Tags Guid? tenantId = null, CancellationToken cancellationToken = default) { - var entityTagIds = await DbContext.EntityTags.AsQueryable() + var entityTagIds = await (await GetDbContextAsync(cancellationToken)).EntityTags.AsQueryable() .Where(q => q.EntityId == entityId && q.TenantId == tenantId) .Select(q => q.TagId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); - var query = GetMongoQueryable() - .Where(x => + var query = (await GetMongoQueryableAsync(cancellationToken)) + .Where(x => x.EntityType == entityType && x.TenantId == tenantId && entityTagIds.Contains(x.Id)); From 4924b016a9c3b2e31f3c30318e21e2ad6d19e1d7 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 4 Jan 2021 11:35:41 +0800 Subject: [PATCH 76/83] Use async repository method in Docs module. --- .../Docs/Documents/EFCoreDocumentRepository.cs | 14 +++++++------- .../Docs/Projects/EfCoreProjectRepository.cs | 14 +++++++------- .../Docs/Documents/MongoDocumentRepository.cs | 18 +++++++++--------- .../Docs/Projects/MongoProjectRepository.cs | 14 +++++++------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Documents/EFCoreDocumentRepository.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Documents/EFCoreDocumentRepository.cs index f096bc10d9..75420f5500 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Documents/EFCoreDocumentRepository.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Documents/EFCoreDocumentRepository.cs @@ -21,7 +21,7 @@ namespace Volo.Docs.Documents public async Task> GetListByProjectId(Guid projectId, CancellationToken cancellationToken = default) { - return await DbSet.Where(d => d.ProjectId == projectId).ToListAsync(cancellationToken: cancellationToken); + return await (await GetDbSetAsync()).Where(d => d.ProjectId == projectId).ToListAsync(cancellationToken: cancellationToken); } public async Task> GetAllAsync( @@ -45,7 +45,7 @@ namespace Volo.Docs.Documents CancellationToken cancellationToken = default) { var query = ApplyFilterForGetAll( - DbSet, + await GetDbSetAsync(), projectId: projectId, name: name, version: version, @@ -87,7 +87,7 @@ namespace Volo.Docs.Documents CancellationToken cancellationToken = default) { var query = ApplyFilterForGetAll( - DbSet, + await GetDbSetAsync(), projectId: projectId, name: name, version: version, @@ -111,7 +111,7 @@ namespace Volo.Docs.Documents bool includeDetails = true, CancellationToken cancellationToken = default) { - return await DbSet.IncludeDetails(includeDetails) + return await (await GetDbSetAsync()).IncludeDetails(includeDetails) .FirstOrDefaultAsync(x => x.ProjectId == projectId && x.Name == name && x.LanguageCode == languageCode && x.Version == version, @@ -127,7 +127,7 @@ namespace Volo.Docs.Documents public async Task GetAsync(Guid id, CancellationToken cancellationToken = default) { - return await DbSet.Where(x => x.Id == id).SingleAsync(cancellationToken: cancellationToken); + return await (await GetDbSetAsync()).Where(x => x.Id == id).SingleAsync(cancellationToken: cancellationToken); } protected virtual IQueryable ApplyFilterForGetAll( @@ -148,7 +148,7 @@ namespace Volo.Docs.Documents DateTime? lastCachedTimeMax, CancellationToken cancellationToken = default) { - return DbSet + return query .WhereIf(projectId.HasValue, d => d.ProjectId == projectId.Value) .WhereIf(name != null, @@ -179,4 +179,4 @@ namespace Volo.Docs.Documents d => d.LastCachedTime.Date <= lastCachedTimeMax.Value.Date); } } -} \ No newline at end of file +} diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs index 835172e679..bf92a8a795 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Projects/EfCoreProjectRepository.cs @@ -20,7 +20,7 @@ namespace Volo.Docs.Projects public async Task> GetListAsync(string sorting, int maxResultCount, int skipCount) { - var projects = await DbSet.OrderBy(sorting ?? "Id desc") + var projects = await (await GetDbSetAsync()).OrderBy(sorting ?? "Id desc") .PageBy(skipCount, maxResultCount) .ToListAsync(); @@ -30,8 +30,8 @@ namespace Volo.Docs.Projects public async Task GetByShortNameAsync(string shortName) { var normalizeShortName = NormalizeShortName(shortName); - - var project = await DbSet.FirstOrDefaultAsync(p => p.ShortName == normalizeShortName); + + var project = await (await GetDbSetAsync()).FirstOrDefaultAsync(p => p.ShortName == normalizeShortName); if (project == null) { @@ -44,13 +44,13 @@ namespace Volo.Docs.Projects public async Task ShortNameExistsAsync(string shortName) { var normalizeShortName = NormalizeShortName(shortName); - - return await DbSet.AnyAsync(x => x.ShortName == normalizeShortName); + + return await (await GetDbSetAsync()).AnyAsync(x => x.ShortName == normalizeShortName); } - + private string NormalizeShortName(string shortName) { return shortName.ToLower(); } } -} \ No newline at end of file +} diff --git a/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Documents/MongoDocumentRepository.cs b/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Documents/MongoDocumentRepository.cs index b3b5210986..d4b0a1c00e 100644 --- a/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Documents/MongoDocumentRepository.cs +++ b/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Documents/MongoDocumentRepository.cs @@ -22,17 +22,17 @@ namespace Volo.Docs.Documents public async Task> GetListByProjectId(Guid projectId, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().Where(d => d.ProjectId == projectId).ToListAsync(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)).Where(d => d.ProjectId == projectId).ToListAsync(cancellationToken); } public async Task FindAsync(Guid projectId, string name, string languageCode, string version, bool includeDetails = true, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().FirstOrDefaultAsync(x => x.ProjectId == projectId && - x.Name == name && - x.LanguageCode == languageCode && - x.Version == version, cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)).FirstOrDefaultAsync(x => x.ProjectId == projectId && + x.Name == name && + x.LanguageCode == languageCode && + x.Version == version, cancellationToken); } public async Task DeleteAsync(Guid projectId, string name, string languageCode, string version, @@ -66,7 +66,7 @@ namespace Volo.Docs.Documents return await ApplyFilterForGetAll( - GetMongoQueryable(), + await GetMongoQueryableAsync(cancellationToken), projectId: projectId, name: name, version: version, @@ -110,7 +110,7 @@ namespace Volo.Docs.Documents return await ApplyFilterForGetAll( - GetMongoQueryable(), + await GetMongoQueryableAsync(cancellationToken), projectId: projectId, name: name, version: version, @@ -132,7 +132,7 @@ namespace Volo.Docs.Documents public async Task GetAsync(Guid id, CancellationToken cancellationToken = default) { - return await GetMongoQueryable().Where(x => x.Id == id).SingleAsync(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)).Where(x => x.Id == id).SingleAsync(cancellationToken); } protected virtual IMongoQueryable ApplyFilterForGetAll( @@ -221,4 +221,4 @@ namespace Volo.Docs.Documents return query; } } -} \ No newline at end of file +} diff --git a/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs b/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs index f1312b9e5d..91f1af9b2a 100644 --- a/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs +++ b/modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Projects/MongoProjectRepository.cs @@ -21,7 +21,7 @@ namespace Volo.Docs.Projects public async Task> GetListAsync(string sorting, int maxResultCount, int skipCount) { - var projects = await GetMongoQueryable().OrderBy(sorting ?? "Id desc").As>() + var projects = await (await GetMongoQueryableAsync()).OrderBy(sorting ?? "Id desc").As>() .PageBy>(skipCount, maxResultCount) .ToListAsync(); @@ -31,8 +31,8 @@ namespace Volo.Docs.Projects public async Task GetByShortNameAsync(string shortName) { var normalizeShortName = NormalizeShortName(shortName); - - var project = await GetMongoQueryable().FirstOrDefaultAsync(p => p.ShortName == normalizeShortName); + + var project = await (await GetMongoQueryableAsync()).FirstOrDefaultAsync(p => p.ShortName == normalizeShortName); if (project == null) { @@ -45,13 +45,13 @@ namespace Volo.Docs.Projects public async Task ShortNameExistsAsync(string shortName) { var normalizeShortName = NormalizeShortName(shortName); - - return await GetMongoQueryable().AnyAsync(x => x.ShortName == normalizeShortName); + + return await (await GetMongoQueryableAsync()).AnyAsync(x => x.ShortName == normalizeShortName); } - + private string NormalizeShortName(string shortName) { return shortName.ToLower(); } } -} \ No newline at end of file +} From 197878ae8a1ebc3a46efb60f2c868f2e71a5198f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 4 Jan 2021 10:42:53 +0300 Subject: [PATCH 77/83] Use GetQueryableAsync in RepositoryAsyncExtensions --- .../Abp/Domain/Repositories/RepositoryAsyncExtensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs index f6191a152f..acc1c3a1bd 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/RepositoryAsyncExtensions.cs @@ -12,13 +12,14 @@ namespace Volo.Abp.Domain.Repositories { #region Contains - public static Task ContainsAsync( + public static async Task ContainsAsync( [NotNull] this IReadOnlyRepository repository, [NotNull] T item, CancellationToken cancellationToken = default) where T : class, IEntity { - return repository.AsyncExecuter.ContainsAsync(repository, item, cancellationToken); + var queryable = await repository.GetQueryableAsync(); + return await repository.AsyncExecuter.ContainsAsync(queryable, item, cancellationToken); } #endregion From 6cd2afa7e4ea94ca5d72460929212892d7ccbadc Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Mon, 4 Jan 2021 11:39:21 +0300 Subject: [PATCH 78/83] deprecate SortOrderIconComponent --- .../components/sort-order-icon/sort-order-icon.component.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/sort-order-icon/sort-order-icon.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/sort-order-icon/sort-order-icon.component.ts index 7e5d62fb6a..439989ef73 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/sort-order-icon/sort-order-icon.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/sort-order-icon/sort-order-icon.component.ts @@ -1,5 +1,8 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; +/** + * @deprecated To be deleted in v5.0. Use ngx-datatale instead. + */ @Component({ selector: 'abp-sort-order-icon', templateUrl: './sort-order-icon.component.html', From a8c5186bde1ca44f00638491b3f2639e17c05b34 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 5 Jan 2021 10:15:32 +0800 Subject: [PATCH 79/83] Update the entity after changing its properties. Resolve #7000 --- .../Volo/Abp/Identity/IdentityUserAppService.cs | 3 +++ 1 file changed, 3 insertions(+) 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 31c9de0e18..9d3b7f5c12 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 @@ -84,7 +84,9 @@ namespace Volo.Abp.Identity input.MapExtraPropertiesTo(user); (await UserManager.CreateAsync(user, input.Password)).CheckErrors(); + await UpdateUserByInput(user, input); + (await UserManager.UpdateAsync(user)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); @@ -174,6 +176,7 @@ namespace Volo.Abp.Identity user.Name = input.Name; user.Surname = input.Surname; + (await UserManager.UpdateAsync(user)).CheckErrors(); if (input.RoleNames != null) { From cb3ea0e5acdfaf1f4689660430ad310b821b828f Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 5 Jan 2021 10:20:15 +0800 Subject: [PATCH 80/83] Remove blank line. --- .../Volo/Abp/Identity/IdentityUserAppService.cs | 1 - 1 file changed, 1 deletion(-) 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 9d3b7f5c12..69fae63d71 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 @@ -84,7 +84,6 @@ namespace Volo.Abp.Identity input.MapExtraPropertiesTo(user); (await UserManager.CreateAsync(user, input.Password)).CheckErrors(); - await UpdateUserByInput(user, input); (await UserManager.UpdateAsync(user)).CheckErrors(); From f67c72d957ac3499a824d932ff05f48efee293fd Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 5 Jan 2021 09:01:12 +0300 Subject: [PATCH 81/83] define VALIDATION_INVALID_CLASSES as a provider --- .../packages/theme-basic/src/lib/theme-basic.module.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts index be08f78e5b..70adcf764e 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts @@ -5,6 +5,7 @@ import { NgbCollapseModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap import { NgxValidateCoreModule, VALIDATION_ERROR_TEMPLATE, + VALIDATION_INVALID_CLASSES, VALIDATION_TARGET_SELECTOR, } from '@ngx-validate/core'; import { AccountLayoutComponent } from './components/account-layout/account-layout.component'; @@ -70,6 +71,10 @@ export class ThemeBasicModule { provide: VALIDATION_TARGET_SELECTOR, useValue: '.form-group', }, + { + provide: VALIDATION_INVALID_CLASSES, + useValue: 'is-invalid', + }, ], }; } From c18225a8de15e756dcda330580612afc2c98798e Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 5 Jan 2021 09:01:25 +0300 Subject: [PATCH 82/83] update the yarn.lock file --- npm/ng-packs/yarn.lock | 626 +++++++++++++++++++++++------------------ 1 file changed, 346 insertions(+), 280 deletions(-) diff --git a/npm/ng-packs/yarn.lock b/npm/ng-packs/yarn.lock index a3f300d1c8..bc2c1e46f5 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -92,14 +92,7 @@ chart.js "^2.9.3" tslib "^2.0.0" -"@abp/utils@^4.1.0-rc.1": - version "4.1.0-rc.1" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-4.1.0-rc.1.tgz#2863867985db9d178a5ce4347309f060f1ce6142" - integrity sha512-C8e+x5/IdkJWQ8gLtO7ygsth5sd1iXKn0ARu/5u0g11nMjHsMY9Qkwg5QrnpHp2ws1+FL1Dg67omrQp9+KK5SA== - dependencies: - just-compare "^1.3.0" - -"@abp/utils@^4.1.0-rc.2": +"@abp/utils@^4.1.0-rc.1", "@abp/utils@^4.1.0-rc.2": version "4.1.0-rc.2" resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-4.1.0-rc.2.tgz#eb6dbf0ee493d0f050b37347d2d6d283098aedae" integrity sha512-V2k5I89lVBoeGIKgg4p2H9GlMAcDWbctwKZPVwBEMVEVm1uTR2xQAWdTdSFd5Q8I8Xsf/aIG8ELM7l5j2h7/zQ== @@ -124,31 +117,31 @@ "@angular-devkit/core" "10.1.7" rxjs "6.6.2" -"@angular-devkit/architect@0.1100.4": - version "0.1100.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1100.4.tgz#68c2b0333daa0291ad99205862111c04e7a63020" - integrity sha512-hzTfcSUwM0jsSt9HvvSFyaoAhX9k73L7y4kmkghzIFhKhIKOp/7o3n7hAFwN/jWKKmVQpPKnYmqzm9H9OveaCQ== +"@angular-devkit/architect@0.1100.5": + version "0.1100.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1100.5.tgz#3cf9b25464d484160b10417668efbdbd15c9e492" + integrity sha512-yOYfucNouc1doTbcGbCNMXGMSc36+j97XpdNoeGyzFQ7GwezLAro0a9gxc5PdOxndfelkND7J1JuOjxdW5O17A== dependencies: - "@angular-devkit/core" "11.0.4" + "@angular-devkit/core" "11.0.5" rxjs "6.6.3" "@angular-devkit/architect@>=0.1000.0 < 0.1100.0": - version "0.1002.0" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1002.0.tgz#470b78aaf79308a23da6a0d3935f2d1f85dcb212" - integrity sha512-twM8V03ujBIGVpgV1PBlSDodUdxtUb7WakutfWafAvEHUsgwzfvQz2VtKWvjNZ9AiYjnCuwkQaclqVv0VHNo9w== + version "0.1002.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1002.1.tgz#bd33dda1361b5d7c23e07b41a603b48ac9c3c744" + integrity sha512-vP27xCe++p3zm+zwSDXDm9/rsM71Q4MYidLLi0MQfo8wxsWS/4mWXycCBoMwDkvW44SPJ4Ds1/F46bb3/xRDvA== dependencies: - "@angular-devkit/core" "10.2.0" + "@angular-devkit/core" "10.2.1" rxjs "6.6.2" "@angular-devkit/build-angular@~0.1100.0": - version "0.1100.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.1100.4.tgz#22596475d38b13735876a4c7e1afc199654bb9ed" - integrity sha512-qVkMbtOwlo+k8fvOBOwwfKWMx06k4I1qrdjpRYAoZCt3cdje4EBepSciLrHnTB+ouIqWxpEDfEXTYBS98tXbBg== - dependencies: - "@angular-devkit/architect" "0.1100.4" - "@angular-devkit/build-optimizer" "0.1100.4" - "@angular-devkit/build-webpack" "0.1100.4" - "@angular-devkit/core" "11.0.4" + version "0.1100.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.1100.5.tgz#36a609a334369d9597ac50731f458440ffdbb2d1" + integrity sha512-lJYsnBImBAqUAIVC2qGY64UaC2uWOPZEpSWjYUxkRZA/c4IVCJj3M12CgONBjtcKYzFVXc1eojhrScukGIJJcg== + dependencies: + "@angular-devkit/architect" "0.1100.5" + "@angular-devkit/build-optimizer" "0.1100.5" + "@angular-devkit/build-webpack" "0.1100.5" + "@angular-devkit/core" "11.0.5" "@babel/core" "7.12.3" "@babel/generator" "7.12.1" "@babel/plugin-transform-runtime" "7.12.1" @@ -156,7 +149,7 @@ "@babel/runtime" "7.12.1" "@babel/template" "7.10.4" "@jsdevtools/coverage-istanbul-loader" "3.0.5" - "@ngtools/webpack" "11.0.4" + "@ngtools/webpack" "11.0.5" ansi-colors "4.1.1" autoprefixer "9.8.6" babel-loader "8.1.0" @@ -223,10 +216,10 @@ "@angular-devkit/architect" "0.1001.7" rxjs "6.6.2" -"@angular-devkit/build-optimizer@0.1100.4": - version "0.1100.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1100.4.tgz#dbe44ad1d4a6e95436e3bae297dafc09a8ab9190" - integrity sha512-C05y4qMb05PWR7l1gZwRQKiB6KIDq+p72r8Yr6jm0UO6raOtMM72R8nHnioMnGJcFtZDEAYXEF+X7soI3MMlfw== +"@angular-devkit/build-optimizer@0.1100.5": + version "0.1100.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1100.5.tgz#25de00e9cbea1444f911aa0a7a53a05800c90d62" + integrity sha512-aKITFuiydR681eS1z84EIdOtqdxP/V5xGZuF3xjGmg5Ddwv36PweAHaCVJEB4btHSWH6uxMvW2hLXg2RTWbRNg== dependencies: loader-utils "2.0.0" source-map "0.7.3" @@ -234,13 +227,13 @@ typescript "4.0.5" webpack-sources "2.0.1" -"@angular-devkit/build-webpack@0.1100.4": - version "0.1100.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1100.4.tgz#8ca4b10ce8fc739b128137c6c7c0d24377d27a76" - integrity sha512-uxe8gNSej3KF1FgqNtJmuRDbbINh3yLtXanXhRxFQLUj8IiNR8IciIVvy6RfXC5gqxcWwy1cOefJLLnuN9AOxQ== +"@angular-devkit/build-webpack@0.1100.5": + version "0.1100.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1100.5.tgz#81be4b35dc90ea66be205ad1cb9dc44dc31bf9e0" + integrity sha512-oD5t2oCfyiCyyeZckrqBnQco94zIMkRnRGzy3lFDH7KMiL0DG9l7x3nxn9H0YunYWr55LsGWwXGoR7l03Kl+jw== dependencies: - "@angular-devkit/architect" "0.1100.4" - "@angular-devkit/core" "11.0.4" + "@angular-devkit/architect" "0.1100.5" + "@angular-devkit/core" "11.0.5" rxjs "6.6.3" "@angular-devkit/core@10.0.8": @@ -265,10 +258,10 @@ rxjs "6.6.2" source-map "0.7.3" -"@angular-devkit/core@10.2.0", "@angular-devkit/core@^10.0.0": - version "10.2.0" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-10.2.0.tgz#fcde160afc2786d2da0166526f065c6cf98684c0" - integrity sha512-XAszFhSF3mZw1VjoOsYGbArr5NJLcStjOvcCGjBPl1UBM2AKpuCQXHxI9XJGYKL3B93Vp5G58d8qkHvamT53OA== +"@angular-devkit/core@10.2.1", "@angular-devkit/core@^10.0.0": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-10.2.1.tgz#3ae38be4ca56c745788481b3577173ac2007e9e0" + integrity sha512-dzlF9Gl7KNt9sPYT2HYq6ySZYwKzkyYR5mrBj3DZOD0OQsoc21LvLkWAHNSL2iYGdHJQS1oJDNs8iRYxYIOY3w== dependencies: ajv "6.12.4" fast-json-stable-stringify "2.1.0" @@ -276,10 +269,10 @@ rxjs "6.6.2" source-map "0.7.3" -"@angular-devkit/core@11.0.4", "@angular-devkit/core@~11.0.2": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-11.0.4.tgz#4128b90bdb4d1803bb246d177b7cc6df64a0fec1" - integrity sha512-LgTvhZ3Ycz0QvNAH/zO1rpQQDn2JN8u9/Awy1gW/XeCC3FYmxeOj/2JCFzlKah3wJv16nMqro5WTppHt8Y++PA== +"@angular-devkit/core@11.0.5", "@angular-devkit/core@~11.0.2": + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-11.0.5.tgz#8239486d2de6c08fc55d2a64f12a7f5d518c8beb" + integrity sha512-hwV8fjF8JNPJkiVWw8MNzeIfDo01aD/OAOlC4L5rQnVHn+i2EiU3brSDmFqyeHPPV3h/QjuBkS3tkN7gSnVWaQ== dependencies: ajv "6.12.6" fast-json-stable-stringify "2.1.0" @@ -329,12 +322,12 @@ ora "5.0.0" rxjs "6.6.2" -"@angular-devkit/schematics@11.0.4", "@angular-devkit/schematics@~11.0.2": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-11.0.4.tgz#0680fe038c66f2ecc3c69a293505fb02b694ce80" - integrity sha512-fFC7qW9A1bFAZgpCfkezBA4WCRzfVFgOzwPpyt65rgSrzw0+EeHjcrUIcXlhyOXAFrTHtA9oLCfEeSjSx5HBEA== +"@angular-devkit/schematics@11.0.5", "@angular-devkit/schematics@~11.0.2": + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-11.0.5.tgz#e5d89451daa644eccce93970709f7cdf44c11982" + integrity sha512-0NKGC8Nf/4vvDpWKB7bwxIazvNnNHnZBX6XlyBXNl+fW8tpTef3PNMJMSErTz9LFnuv61vsKbc36u/Ek2YChWg== dependencies: - "@angular-devkit/core" "11.0.4" + "@angular-devkit/core" "11.0.5" ora "5.1.0" rxjs "6.6.3" @@ -347,9 +340,9 @@ rxjs "6.4.0" "@angular/animations@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-11.0.4.tgz#fa669490d039455e63413a6b8cd1ff6b7a966bec" - integrity sha512-NI7UdLNdzTfLCDu0zVqwhdKq2z1flRsM2GCD9RHG/NRjlohh73uRTBW+BcYpfh+o+Wq4giiq8UkTIgS2ReqDGg== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-11.0.5.tgz#44157c8bbb3f20ce1d3d6386eae956659cefd9d7" + integrity sha512-ghE/xDTYuEWkKNZtioH9JBrSlux0MLHzWoE7tNP+XMaplt80lCm979vWsEBO3/xpQLRmRlGPul6RacCAoeqogg== dependencies: tslib "^2.0.0" @@ -363,19 +356,19 @@ parse5 "^5.0.0" "@angular/cli@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-11.0.4.tgz#a04724f7ffb27417df59c2359e47ec54e1f61fab" - integrity sha512-VkE/gx6P80EJHg13fG+gkZfd2DJmRaDAtnamcCGM4AThzoUN9XBdxc24uMLEzBb0/mJ4vpMK9+WTNIdMmzl+Tg== - dependencies: - "@angular-devkit/architect" "0.1100.4" - "@angular-devkit/core" "11.0.4" - "@angular-devkit/schematics" "11.0.4" - "@schematics/angular" "11.0.4" - "@schematics/update" "0.1100.4" + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-11.0.5.tgz#1066d290fc91460f98cedcfbc9a5736340661467" + integrity sha512-k4j/2z7qkuigJ1shH0McW1wW63clhrbrg98FK4/KWhU/sce5AgVjuHDQFycAclTwHesf7Vs6Gzt7zGlqUmeKIg== + dependencies: + "@angular-devkit/architect" "0.1100.5" + "@angular-devkit/core" "11.0.5" + "@angular-devkit/schematics" "11.0.5" + "@schematics/angular" "11.0.5" + "@schematics/update" "0.1100.5" "@yarnpkg/lockfile" "1.1.0" ansi-colors "4.1.1" debug "4.2.0" - ini "1.3.5" + ini "1.3.6" inquirer "7.3.3" npm-package-arg "8.1.0" npm-pick-manifest "6.1.0" @@ -389,9 +382,9 @@ uuid "8.3.1" "@angular/common@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-11.0.4.tgz#39cd88bfcecd895419c059c366eac2df2ca6a2e9" - integrity sha512-4R2ALj71J6EAHVCKNnHHCKL7wcosMsv3gcMXbMTE+Wpzo3khEhM0Tej+I1qmMbVmGXVlRb//4+rjE4gff6FvQw== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-11.0.5.tgz#7ec508cb7e14cf38640fe4e1c0fa3dd322a52505" + integrity sha512-aoXdTkoni65LWhrPKNsAiOnO70XFaTaisO+K8ZYMpciMTTAxHx3hFCF9sj4a+Bo3M1a5UDjpsFDYMeGgJOkmFA== dependencies: tslib "^2.0.0" @@ -434,23 +427,23 @@ integrity sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w== "@angular/core@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-11.0.4.tgz#8eebb6a550dc24e4d53f642c8a78a0da2830cd5b" - integrity sha512-860cTMjdCHcvEsHOsTzpg5rThxwVgtnY4yT0SgboWiphrlzX+aNoyN/cCJHxWhmOTRlrl6/+hkeRq95E2BZkKw== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-11.0.5.tgz#b8c448c3cd4f6dae7327cc1ba4ee2aa29c8dbc26" + integrity sha512-XAXWQi7R3ucZXQwx9QK5jSKJeQyRJ53u2dQDpr7R5stzeCy1a5hrNOkZLg9zOTTPcth/6+FrOrRZP9SMdxtw3w== dependencies: tslib "^2.0.0" "@angular/forms@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-11.0.4.tgz#6d77f01ecdf027a78df18d4e6cd3ad8fc8dd49e4" - integrity sha512-Fhfc4buwMZk0WumDvl/X7XBnOKFeTRTJrwKdi8LlhY6o1Og8H4e/f69u9iDJCF3YjU4qC6yGtPp9YpSVCPP7Ew== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-11.0.5.tgz#1be90f86b45a3d672eecea249b1d8e5e9f8f0bc3" + integrity sha512-2zB1IuqYNJrjh7Og9J8f/AtjX3NHc3VVbt0rPw35ghqIU3aQLpOichdQ1y5QvMWic1UzZ7SjWXDU7RpKbm4iUA== dependencies: tslib "^2.0.0" "@angular/language-service@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-11.0.4.tgz#0a9c01170be92378f217dea3263c4eb2f8411aaa" - integrity sha512-KtQxVSlZi3SwZEN4E56KHkNTFEYa3FPZfLJFm6WD1dSobFyMwJgvztO08GWSaT4S0ht0NNRD2IRt0XzBYuZkag== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-11.0.5.tgz#92499b5f29509142f29ae7af64b049765a7f7050" + integrity sha512-EzGycD9ztTKAZB+kR+masNqCfGmU0vnKd/z33VLmeo9fo41t/YNCEQEEFz/pEl2dEwX/Wjou+3oyTYZIZz2uSA== "@angular/localize@~10.0.10": version "10.0.14" @@ -462,32 +455,32 @@ yargs "15.3.0" "@angular/localize@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-11.0.4.tgz#8f7a36685d97f26d52e3f19d9218e1e2e05a2bb2" - integrity sha512-r0dWvwFvEqQJ/H94rr548S092Hq53RqyMANuFD09CpkWXS6yAWBfArB6mW77PARnicEC0zkbi5qMGACjtSyNtA== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-11.0.5.tgz#e770d4ec1b2094822fdb0524516dca6bf39dfd05" + integrity sha512-tvzgRa/t0xCouCPFMurqZImLeWIISUjVEzkcny9P7xaaz0Cw7kSyulc0e8HXf+8oijSJ624YOYUzr7mkPoIfew== dependencies: "@babel/core" "7.8.3" glob "7.1.2" yargs "^16.1.1" "@angular/platform-browser-dynamic@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.0.4.tgz#d775f12954db689507ef98a51d8d7ed5763becd4" - integrity sha512-ZOWTZaFfZSHhMy7a0RIxipiZoiobHWrGlq8/YaMrIgzUb9Fv518FeFCCI68BP0/GuyxX74MJmzv4ZgQctKKxXw== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.0.5.tgz#1e1de1ca429d85eb43b14cd5da90eba4ac95bd76" + integrity sha512-MFjpQcqkHOu8iTUMKVG6vfuOHwrRlgPBvkNucEbtXhTTYNlsw2mprxfUODYEu26EBUAh+FGttu8ZjclUGw4bVg== dependencies: tslib "^2.0.0" "@angular/platform-browser@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-11.0.4.tgz#131db1115943eb9c0191080e200c1e9dbd214d4c" - integrity sha512-+uUCKJgspSghJ3R6Fk0XHA0tolbaRBi8JFS2cY+hi9s27WKB88peGvtsK6RCOPJONY6JdOuhpcZqRN8dKfPi7w== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-11.0.5.tgz#b695d2533491f85721612a41d6d3708791bca96c" + integrity sha512-173JZHF3QS78hEscBxFZ/kX8KLjdaDhfAYi4Sh8daIKNUcDcyhqEy7wpAjWmCwdspL1QUtWKCrhZqrEVNGTpvA== dependencies: tslib "^2.0.0" "@angular/router@~11.0.0": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-11.0.4.tgz#324507346c508649135f56e5f2b57c60e0ba7b16" - integrity sha512-B0sqv8zMM6j88+udEZzO8wKBw61pHgWZmLopnAqA65rRPrAvMsvAHUnYqX6w5pYqhJQxCVLVeKM+0QlQh1+WnA== + version "11.0.5" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-11.0.5.tgz#95d47b3b510f6a49597db64cfd7ef936bb24c402" + integrity sha512-mSD4tbzuFH4uBb9vxPQHBUbkIMoWAfVUb7r9gtn3/deOxQbVh08f2gk2iWDN3OQLAa5mNHswuLByAYSw2rPbMA== dependencies: tslib "^2.0.0" @@ -506,10 +499,10 @@ "@ant-design/colors" "^5.0.0" tslib "^2.0.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.11", "@babel/code-frame@^7.8.3": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== dependencies: "@babel/highlight" "^7.10.4" @@ -591,12 +584,12 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.12.1", "@babel/generator@^7.12.10", "@babel/generator@^7.8.3": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.10.tgz#2b188fc329fb8e4f762181703beffc0fe6df3460" - integrity sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww== +"@babel/generator@^7.12.1", "@babel/generator@^7.12.10", "@babel/generator@^7.12.11", "@babel/generator@^7.8.3": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af" + integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA== dependencies: - "@babel/types" "^7.12.10" + "@babel/types" "^7.12.11" jsesc "^2.5.1" source-map "^0.5.0" @@ -660,16 +653,16 @@ dependencies: "@babel/types" "^7.12.1" -"@babel/helper-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" - integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== +"@babel/helper-function-name@^7.10.4", "@babel/helper-function-name@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz#1fd7738aee5dcf53c3ecff24f1da9c511ec47b42" + integrity sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA== dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/helper-get-function-arity" "^7.12.10" + "@babel/template" "^7.12.7" + "@babel/types" "^7.12.11" -"@babel/helper-get-function-arity@^7.10.4": +"@babel/helper-get-function-arity@^7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz#b158817a3165b5faa2047825dfa61970ddcc16cf" integrity sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag== @@ -683,7 +676,7 @@ dependencies: "@babel/types" "^7.10.4" -"@babel/helper-member-expression-to-functions@^7.12.1": +"@babel/helper-member-expression-to-functions@^7.12.1", "@babel/helper-member-expression-to-functions@^7.12.7": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855" integrity sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw== @@ -712,7 +705,7 @@ "@babel/types" "^7.12.1" lodash "^4.17.19" -"@babel/helper-optimise-call-expression@^7.10.4": +"@babel/helper-optimise-call-expression@^7.10.4", "@babel/helper-optimise-call-expression@^7.12.10": version "7.12.10" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz#94ca4e306ee11a7dd6e9f42823e2ac6b49881e2d" integrity sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ== @@ -734,14 +727,14 @@ "@babel/types" "^7.12.1" "@babel/helper-replace-supers@^7.12.1": - version "7.12.5" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz#f009a17543bbbbce16b06206ae73b63d3fca68d9" - integrity sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA== + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz#ea511658fc66c7908f923106dd88e08d1997d60d" + integrity sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.12.1" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.12.5" - "@babel/types" "^7.12.5" + "@babel/helper-member-expression-to-functions" "^7.12.7" + "@babel/helper-optimise-call-expression" "^7.12.10" + "@babel/traverse" "^7.12.10" + "@babel/types" "^7.12.11" "@babel/helper-simple-access@^7.12.1": version "7.12.1" @@ -757,22 +750,22 @@ dependencies: "@babel/types" "^7.12.1" -"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" - integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== +"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0", "@babel/helper-split-export-declaration@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz#1b4cc424458643c47d37022223da33d76ea4603a" + integrity sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g== dependencies: - "@babel/types" "^7.11.0" + "@babel/types" "^7.12.11" -"@babel/helper-validator-identifier@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" - integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== +"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" + integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== "@babel/helper-validator-option@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz#175567380c3e77d60ff98a54bb015fe78f2178d9" - integrity sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A== + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f" + integrity sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw== "@babel/helper-wrap-function@^7.10.4": version "7.12.3" @@ -802,15 +795,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.12.10", "@babel/parser@^7.12.3", "@babel/parser@^7.12.7", "@babel/parser@^7.8.3": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.10.tgz#824600d59e96aea26a5a2af5a9d812af05c3ae81" - integrity sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA== +"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.3", "@babel/parser@^7.12.7", "@babel/parser@^7.8.3": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79" + integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg== "@babel/plugin-proposal-async-generator-functions@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz#dc6c1170e27d8aca99ff65f4925bd06b1c90550e" - integrity sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A== + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.12.tgz#04b8f24fd4532008ab4e79f788468fd5a8476566" + integrity sha512-nrz9y0a4xmUrRq51bYkWJIO5SBZyG2ys2qinHsN0zHDHVsUaModrkpyWWWXfGqYQmOL3x9sQIcTNN/pBGpo09A== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-remap-async-to-generator" "^7.12.1" @@ -1036,9 +1029,9 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-block-scoping@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz#f0ee727874b42a208a48a586b84c3d222c2bbef1" - integrity sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w== + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz#d93a567a152c22aea3b1929bb118d1d0a175cdca" + integrity sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ== dependencies: "@babel/helper-plugin-utils" "^7.10.4" @@ -1387,26 +1380,26 @@ "@babel/types" "^7.12.7" "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.5", "@babel/traverse@^7.8.3": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.10.tgz#2d1f4041e8bf42ea099e5b2dc48d6a594c00017a" - integrity sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.10" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.12.10" - "@babel/types" "^7.12.10" + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.12.tgz#d0cd87892704edd8da002d674bc811ce64743376" + integrity sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w== + dependencies: + "@babel/code-frame" "^7.12.11" + "@babel/generator" "^7.12.11" + "@babel/helper-function-name" "^7.12.11" + "@babel/helper-split-export-declaration" "^7.12.11" + "@babel/parser" "^7.12.11" + "@babel/types" "^7.12.12" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.10.tgz#7965e4a7260b26f09c56bcfcb0498af1f6d9b260" - integrity sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw== +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.12", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" + integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ== dependencies: - "@babel/helper-validator-identifier" "^7.10.4" + "@babel/helper-validator-identifier" "^7.12.11" lodash "^4.17.19" to-fast-properties "^2.0.0" @@ -2473,12 +2466,12 @@ jquery "3.5.0" replace-in-file "^4.1.3" -"@ngtools/webpack@11.0.4": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-11.0.4.tgz#fd80a8b7d648ddb8e56d73404e6b673903d2d365" - integrity sha512-MAV7inQmsMISTnDcXwyRX5oJZx8F7K/tZRLJciQwkM0DqZyq8fI9KDRwBcmYeQ+J0mSJV9LUVdExmpulpkywqw== +"@ngtools/webpack@11.0.5": + version "11.0.5" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-11.0.5.tgz#9d1abb9f9a5e72c014b5ed3e0c2cefe2a4175b30" + integrity sha512-hM0LdOSlC6c7ij+BvIpAFbe7dpJhL+A51L5v6YbMA6aM0Sb/y+HpE2u34AHEQvute7cLe4EyOyvJ9jSinVAJhQ== dependencies: - "@angular-devkit/core" "11.0.4" + "@angular-devkit/core" "11.0.5" enhanced-resolve "5.3.1" webpack-sources "2.0.1" @@ -2510,18 +2503,18 @@ dependencies: tslib "^1.9.0" -"@nodelib/fs.scandir@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" - integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== +"@nodelib/fs.scandir@2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" + integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA== dependencies: - "@nodelib/fs.stat" "2.0.3" + "@nodelib/fs.stat" "2.0.4" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" - integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== +"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" + integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== "@nodelib/fs.stat@^1.1.2": version "1.1.3" @@ -2529,11 +2522,11 @@ integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== "@nodelib/fs.walk@^1.2.3": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" - integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + version "1.2.6" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" + integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow== dependencies: - "@nodelib/fs.scandir" "2.1.3" + "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" "@npmcli/move-file@^1.0.1": @@ -2559,10 +2552,10 @@ is-plain-object "^5.0.0" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-2.0.0.tgz#6d8f8ad9db3b75a39115f5def2654df8bed39f28" - integrity sha512-J4bfM7lf8oZvEAdpS71oTvC1ofKxfEZgU5vKVwzZKi4QPiL82udjpseJwxPid9Pu2FNmyRQOX4iEj6W1iOSnPw== +"@octokit/openapi-types@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-2.0.1.tgz#7453d8281ce66b8ed1607f7ac7d751c3baffd2cc" + integrity sha512-9AuC04PUnZrjoLiw3uPtwGh9FE4Q3rTqs51oNlQ0rkwgE8ftYsOC+lsrQyvCvWm85smBbSc0FNRKKumvGyb44Q== "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" @@ -2651,11 +2644,11 @@ "@types/node" ">= 8" "@octokit/types@^6.0.0", "@octokit/types@^6.0.3": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.1.1.tgz#bc88b3eb5f447b025a2a1a8177a72db216e8d4ca" - integrity sha512-btm3D6S7VkRrgyYF31etUtVY/eQ1KzrNRqhFt25KSe2mKlXuLXJilglRC6eDA2P6ou94BUnk/Kz5MPEolXgoiw== + version "6.1.2" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.1.2.tgz#2b3a6ae0b8b71c27c770b4ff3e9ad8f1f538af58" + integrity sha512-LPCpcLbcky7fWfHCTuc7tMiSHFpFlrThJqVdaHgowBTMS0ijlZFfonQC/C1PrZOjD4xRCYgBqH9yttEATGE/nw== dependencies: - "@octokit/openapi-types" "^2.0.0" + "@octokit/openapi-types" "^2.0.1" "@types/node" ">= 8" "@rollup/plugin-commonjs@^15.0.0": @@ -2699,13 +2692,13 @@ estree-walker "^1.0.1" picomatch "^2.2.2" -"@schematics/angular@11.0.4": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-11.0.4.tgz#36268ebda718c4f395457d2eea874fda9c469402" - integrity sha512-LwBD9TIoLy9XqqInJvlN4BHtPyJExyeorNiOp6rXb/wafuDbvZ+9kY9GWZTY1auVo5PNKqErfxr74ydA3FFb9g== +"@schematics/angular@11.0.5": + version "11.0.5" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-11.0.5.tgz#149f908fd600e881ff87c5192d2673d0e3c37f38" + integrity sha512-7p2wweoJYhim8YUy3ih1SrPGqRsa6+aEFbYgo9v4zt7b3tOva8SvkbC2alayK74fclzQ7umqa6xAwvWhy8ORvg== dependencies: - "@angular-devkit/core" "11.0.4" - "@angular-devkit/schematics" "11.0.4" + "@angular-devkit/core" "11.0.5" + "@angular-devkit/schematics" "11.0.5" jsonc-parser "2.3.1" "@schematics/angular@~10.0.5": @@ -2724,15 +2717,15 @@ "@angular-devkit/core" "10.1.7" "@angular-devkit/schematics" "10.1.7" -"@schematics/update@0.1100.4": - version "0.1100.4" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.1100.4.tgz#b67efdb39396ddcacef97de008100944af3d1556" - integrity sha512-YwFtgxCQQkYC89IC7dfshyGr0roE6bpp5HgpQLdS/AOjHeZKo7/SPdM0W4ddB+Fml1Fo6v4eFG/Ia9oR7qNv1A== +"@schematics/update@0.1100.5": + version "0.1100.5" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.1100.5.tgz#40b529d93db51e6f66378bd9f4ff99f2e9c278f6" + integrity sha512-BYtKKuiWsrlc4FMW3bRyl4tm6lWNMTi8oql/mtkSgH7V5eMmaLDJtM+zDl+qyC/KHPxbHTfoHDapfv1tITSWjA== dependencies: - "@angular-devkit/core" "11.0.4" - "@angular-devkit/schematics" "11.0.4" + "@angular-devkit/core" "11.0.5" + "@angular-devkit/schematics" "11.0.5" "@yarnpkg/lockfile" "1.1.0" - ini "1.3.5" + ini "1.3.6" npm-package-arg "^8.0.0" pacote "9.5.12" semver "7.3.2" @@ -2930,14 +2923,14 @@ integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== "@types/node@*", "@types/node@>= 8": - version "14.14.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.13.tgz#9e425079799322113ae8477297ae6ef51b8e0cdf" - integrity sha512-vbxr0VZ8exFMMAjCW8rJwaya0dMCDyYW2ZRdTyjtrCvJoENMpdUHOT/eTzvgyA5ZnqRZ/sI0NwqAxNHKYokLJQ== + version "14.14.19" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.19.tgz#5135176a8330b88ece4e9ab1fdcfc0a545b4bab4" + integrity sha512-4nhBPStMK04rruRVtVc6cDqhu7S9GZai0fpXgPXrFpcPX6Xul8xnrjSdGB4KPBVYG/R5+fXWdCM8qBoiULWGPQ== "@types/node@^12.11.1": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== + version "12.19.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.11.tgz#9220ab4b20d91169eb78f456dbfcbabee89dfb50" + integrity sha512-bwVfNTFZOrGXyiQ6t4B9sZerMSShWNsGRw8tC5DY1qImUNczS9SjT4G6PnzjCnxsu5Ubj6xjL2lgwddkxtQl5w== "@types/node@^8.0.31": version "8.10.66" @@ -3015,9 +3008,9 @@ source-map "^0.6.1" "@types/yargs-parser@*": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" - integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + version "20.2.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" + integrity sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA== "@types/yargs@^13.0.0": version "13.0.11" @@ -3027,9 +3020,9 @@ "@types/yargs-parser" "*" "@types/yargs@^15.0.0": - version "15.0.11" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.11.tgz#361d7579ecdac1527687bcebf9946621c12ab78c" - integrity sha512-jfcNBxHFYJ4nPIacsi3woz1+kvUO6s1CyeEhtnDHBjHUMNj5UlW2GynmnSgiJJEdNg9yW5C8lfoNRZrHGv5EqA== + version "15.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.12.tgz#6234ce3e3e3fa32c5db301a170f96a599c960d74" + integrity sha512-f+fD/fQAo3BCbCDlrUpznF1A5Zp9rB0noS5vnoormHSIPFKL0Z2DcUJ3Gxp5ytH4uLRNxy7AwYUC9exZzqGMAw== dependencies: "@types/yargs-parser" "*" @@ -3761,7 +3754,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-js@^1.0.2: +base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -3818,6 +3811,15 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" +bl@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" + integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + blocking-proxy@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" @@ -3987,7 +3989,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.15.0, browserslist@^4.7.0, browserslist@^4.9.1: +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.7.0, browserslist@^4.9.1: version "4.16.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.0.tgz#410277627500be3cb28a1bfe037586fbedf9488b" integrity sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ== @@ -4048,15 +4050,23 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= builtin-modules@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484" - integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" + integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== builtin-status-codes@^3.0.0: version "3.0.0" @@ -4264,9 +4274,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001165: - version "1.0.30001166" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001166.tgz#ca73e8747acfd16a4fd6c4b784f1b995f9698cf8" - integrity sha512-nCL4LzYK7F4mL0TjEMeYavafOGnBa98vTudH5c8lW9izUjnB99InG6pmC1ElAI1p0GlyZajv4ltUdFXvOHIl1A== + version "1.0.30001173" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001173.tgz#3c47bbe3cd6d7a9eda7f50ac016d158005569f56" + integrity sha512-R3aqmjrICdGCTAnSXtNyvWYMK3YtV5jwudbq0T7nN9k4kmE4CBuwPqyJ+KBzepSTh0huivV2gLbSMEzTTmfeYw== canonical-path@1.0.0: version "1.0.0" @@ -4447,7 +4457,7 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-spinners@^2.0.0, cli-spinners@^2.2.0, cli-spinners@^2.4.0: +cli-spinners@^2.0.0, cli-spinners@^2.2.0, cli-spinners@^2.4.0, cli-spinners@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.5.0.tgz#12763e47251bf951cb75c201dfa58ff1bcb2d047" integrity sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ== @@ -4829,16 +4839,16 @@ conventional-changelog-core@^3.1.6: through2 "^3.0.0" conventional-changelog-core@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.1.tgz#f811ad98ab2ff080becafc61407509420c9b447d" - integrity sha512-8cH8/DEoD3e5Q6aeogdR5oaaKs0+mG6+f+Om0ZYt3PNv7Zo0sQhu4bMDRsqAF+UTekTAtP1W/C41jH/fkm8Jtw== + version "4.2.2" + resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.2.tgz#f0897df6d53b5d63dec36b9442bd45354f8b3ce5" + integrity sha512-7pDpRUiobQDNkwHyJG7k9f6maPo9tfPzkSWbRq97GGiZqisElhnvUZSvyQH20ogfOjntB5aadvv6NNcKL1sReg== dependencies: add-stream "^1.0.0" conventional-changelog-writer "^4.0.18" conventional-commits-parser "^3.2.0" dateformat "^3.0.0" get-pkg-repo "^1.0.0" - git-raw-commits "2.0.0" + git-raw-commits "^2.0.8" git-remote-origin-url "^2.0.0" git-semver-tags "^4.1.1" lodash "^4.17.15" @@ -4891,9 +4901,9 @@ conventional-changelog-preset-loader@^2.1.1, conventional-changelog-preset-loade integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== conventional-changelog-writer@^4.0.18, conventional-changelog-writer@^4.0.6: - version "4.0.18" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.18.tgz#10b73baa59c7befc69b360562f8b9cd19e63daf8" - integrity sha512-mAQDCKyB9HsE8Ko5cCM1Jn1AWxXPYV0v8dFPabZRkvsiWUul2YyAqbIaoMKF88Zf2ffnOPSvKhboLf3fnjo5/A== + version "4.1.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz#1ca7880b75aa28695ad33312a1f2366f4b12659f" + integrity sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw== dependencies: compare-func "^2.0.0" conventional-commits-filter "^2.0.7" @@ -4990,6 +5000,13 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +copy-anything@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.1.tgz#2afbce6da684bdfcbec93752fa762819cb480d9a" + integrity sha512-lA57e7viQHOdPQcrytv5jFeudZZOXuyk47lZym279FiDQ8jeZomXiGuVf6ffMKkJ+3TIai3J1J3yi6M+/4U35g== + dependencies: + is-what "^3.7.1" + copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" @@ -5025,11 +5042,11 @@ copy-webpack-plugin@6.2.1: webpack-sources "^1.4.3" core-js-compat@^3.6.2: - version "3.8.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.1.tgz#8d1ddd341d660ba6194cbe0ce60f4c794c87a36e" - integrity sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ== + version "3.8.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.2.tgz#3717f51f6c3d2ebba8cbf27619b57160029d1d4c" + integrity sha512-LO8uL9lOIyRRrQmZxHZFl1RV+ZbcsAkFWTktn5SmH40WgLtSNYN4m4W2v9ONT147PxBY/XrRhrWq8TlvObyUjQ== dependencies: - browserslist "^4.15.0" + browserslist "^4.16.0" semver "7.0.0" core-js@3.6.5: @@ -5398,6 +5415,11 @@ dargs@^4.0.1: dependencies: number-is-nan "^1.0.0" +dargs@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" + integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -5811,9 +5833,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.621: - version "1.3.626" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.626.tgz#48acdf322be07feb2c1330ba05e4bf6327f721a3" - integrity sha512-7CanEvJx74EnvjHu1X8gf93KieyxvFLnqOXAH/ddjWD4RrUZYqdg3pykrQ/7t6SLI7DTsp4tfQXEfzeK5t6oAw== + version "1.3.633" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.633.tgz#16dd5aec9de03894e8d14a1db4cda8a369b9b7fe" + integrity sha512-bsVCsONiVX1abkWdH7KtpuDAhsQ3N3bjPYhROSAXE78roJKet0Y5wznA14JE9pzbwSZmSMAW6KiKYf1RvbTJkA== elliptic@^6.5.3: version "6.5.3" @@ -5905,9 +5927,9 @@ err-code@^1.0.0: integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== dependencies: prr "~1.0.1" @@ -6349,9 +6371,9 @@ fastparse@^1.1.2: integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== fastq@^1.6.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.9.0.tgz#e16a72f338eaca48e91b5c23593bcc2ef66b7947" - integrity sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w== + version "1.10.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.10.0.tgz#74dbefccade964932cdf500473ef302719c652bb" + integrity sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA== dependencies: reusify "^1.0.4" @@ -6691,9 +6713,9 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-intrinsic@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be" - integrity sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49" + integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg== dependencies: function-bind "^1.1.1" has "^1.0.3" @@ -6762,6 +6784,17 @@ git-raw-commits@2.0.0: split2 "^2.0.0" through2 "^2.0.0" +git-raw-commits@^2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.9.tgz#5cbc707a615cb77b71e687f8a1ee54af46208b22" + integrity sha512-hSpNpxprVno7IOd4PZ93RQ+gNdzPAIrW0x8av6JQDJGV4k1mR9fE01dl8sEqi2P7aKmmwiGUn1BCPuf16Ae0Qw== + dependencies: + dargs "^7.0.0" + lodash.template "^4.0.2" + meow "^8.0.0" + split2 "^3.0.0" + through2 "^4.0.0" + git-remote-origin-url@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" @@ -7155,9 +7188,9 @@ html-encoding-sniffer@^1.0.2: whatwg-encoding "^1.0.1" html-entities@^1.3.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.3.tgz#3dca638a43ee7de316fc23067398491152ad4736" - integrity sha512-/VulV3SYni1taM7a4RMdceqzJWR39gpZHjBwUnsCFKWV/GJkD14CJ5F7eWcZozmHJK0/f/H5U3b3SiPkuvxMgg== + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== html-escaper@^2.0.0: version "2.0.2" @@ -7212,9 +7245,9 @@ http-errors@~1.7.2: toidentifier "1.0.0" http-parser-js@>=0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.2.tgz#da2e31d237b393aae72ace43882dd7e270a8ff77" - integrity sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ== + version "0.5.3" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" + integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== http-proxy-agent@^2.1.0: version "2.1.0" @@ -7306,7 +7339,7 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" -ieee754@^1.1.4: +ieee754@^1.1.13, ieee754@^1.1.4: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -7352,9 +7385,9 @@ import-fresh@^2.0.0: resolve-from "^3.0.0" import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e" - integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw== + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -7430,10 +7463,10 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +ini@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.6.tgz#f1c46a2a93a253e7b3905115e74d527cd23061a1" + integrity sha512-IZUoxEjNjubzrmvzZU4lKP7OnYmX72XRl3sqkfJhBKweKi5rnGi5+IUdlj/H1M+Ip5JQ1WzaDMOBRY90Ajc5jg== ini@^1.3.2, ini@^1.3.4: version "1.3.8" @@ -7894,6 +7927,11 @@ is-utf8@^0.2.0, is-utf8@^0.2.1: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= +is-what@^3.7.1: + version "3.12.0" + resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.12.0.tgz#f4405ce4bd6dd420d3ced51a026fb90e03705e55" + integrity sha512-2ilQz5/f/o9V7WRWJQmpFYNmQFZ9iM+OXRonZKcYgTkCzjb949Vi4h282PD1UfmgHk666rcWonbRJ++KI41VGw== + is-windows@^1.0.0, is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -8708,10 +8746,11 @@ less@3.12.2: source-map "~0.6.0" less@^3.10.3: - version "3.13.0" - resolved "https://registry.yarnpkg.com/less/-/less-3.13.0.tgz#6a47bb19d97edcf7a53d444b099275dd6b17c85a" - integrity sha512-uPhr9uoSGVKKYVGz0rXcYBK1zjwcIWRGcbnSgNt66XuIZYrYPaQiS+LeUOvqedBwrwdBYYaLqSff5ytGYuT7rA== + version "3.13.1" + resolved "https://registry.yarnpkg.com/less/-/less-3.13.1.tgz#0ebc91d2a0e9c0c6735b83d496b0ab0583077909" + integrity sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw== dependencies: + copy-anything "^2.0.1" tslib "^1.10.0" optionalDependencies: errno "^0.1.1" @@ -9141,9 +9180,9 @@ meow@^4.0.0: trim-newlines "^2.0.0" meow@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.0.0.tgz#1aa10ee61046719e334ffdc038bb5069250ec99a" - integrity sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg== + version "8.1.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.0.tgz#0fcaa267e35e4d58584b8205923df6021ddcc7ba" + integrity sha512-fNWkgM1UVMey2kf24yLiccxLihc5W+6zVus3/N0b+VfnJgxV99E9u04X6NAiKdg6ED7DAQBX5sy36NM0QJZkWA== dependencies: "@types/minimist" "^1.2.0" camelcase-keys "^6.2.2" @@ -9224,22 +9263,17 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -"mime-db@>= 1.43.0 < 2": +mime-db@1.45.0, "mime-db@>= 1.43.0 < 2": version "1.45.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + version "2.1.28" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd" + integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ== dependencies: - mime-db "1.44.0" + mime-db "1.45.0" mime@1.6.0, mime@^1.4.1: version "1.6.0" @@ -9247,9 +9281,9 @@ mime@1.6.0, mime@^1.4.1: integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mime@^2.3.1, mime@^2.4.4: - version "2.4.6" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" - integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== + version "2.4.7" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.7.tgz#962aed9be0ed19c91fd7dc2ece5d7f4e89a90d74" + integrity sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA== mimic-fn@^1.0.0: version "1.2.0" @@ -9589,9 +9623,9 @@ ng-packagr@^11.0.1: terser "^5.0.0" ng-zorro-antd@^10.1.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/ng-zorro-antd/-/ng-zorro-antd-10.2.1.tgz#06d9c2db7f92bdd560c98c201114b2fc2318af23" - integrity sha512-G1w/Gs2Qgsoyf9c+t1uyQkZ07ayiOoH4waS8CP+IEvlCe0fZ02V0IFjS6NLrTpDxw7qDBIykI+qcWEY14GIF8A== + version "10.2.2" + resolved "https://registry.yarnpkg.com/ng-zorro-antd/-/ng-zorro-antd-10.2.2.tgz#5951f1fd5d1e405e7fe983756dca1eb942b255de" + integrity sha512-4Q2G6DtRJnEQXFcIEUyqgFi6JXcEF9bN0zOPNBV7LTNgjOf31QiE+3Pu2ifz8esGVwv7vmG8if8V2/Ha/Ol8Dw== dependencies: "@angular/cdk" "^10.2.4" "@ant-design/icons-angular" "^10.0.0" @@ -10085,7 +10119,7 @@ ora@5.0.0: strip-ansi "^6.0.0" wcwidth "^1.0.1" -ora@5.1.0, ora@^5.1.0: +ora@5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/ora/-/ora-5.1.0.tgz#b188cf8cd2d4d9b13fd25383bc3e5cba352c94f8" integrity sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w== @@ -10111,6 +10145,20 @@ ora@^3.4.0: strip-ansi "^5.2.0" wcwidth "^1.0.1" +ora@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.2.0.tgz#de10bfd2d15514384af45f3fa9d9b1aaf344fda1" + integrity sha512-+wG2v8TUU8EgzPHun1k/n45pXquQ9fHnbXVetl9rRgO6kjZszGGbraF3XPTIdgeA+s1lbRjSEftAnyT0w8ZMvQ== + dependencies: + bl "^4.0.3" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + log-symbols "^4.0.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" @@ -11371,7 +11419,7 @@ read@1, read@~1.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.6.0: +"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -11921,9 +11969,9 @@ sass@1.27.0: chokidar ">=2.0.0 <4.0.0" sass@^1.23.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.30.0.tgz#60bbbbaf76ba10117e61c6c24f00161c3d60610e" - integrity sha512-26EUhOXRLaUY7+mWuRFqGeGGNmhB1vblpTENO1Z7mAzzIZeVxZr9EZoaY1kyGLFWdSOZxRMAufiN2mkbO6dAlw== + version "1.32.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.0.tgz#10101a026c13080b14e2b374d4e15ee24400a4d3" + integrity sha512-fhyqEbMIycQA4blrz/C0pYhv2o4x2y6FYYAH0CshBw3DXh5D5wyERgxw0ptdau1orc/GhNrhF7DFN2etyOCEng== dependencies: chokidar ">=2.0.0 <4.0.0" @@ -12442,6 +12490,13 @@ split2@^2.0.0: dependencies: through2 "^2.0.2" +split2@^3.0.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + split@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" @@ -13350,9 +13405,9 @@ typescript@^3.5.2, typescript@~3.9.2: integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== uglify-js@^3.1.4: - version "3.12.1" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.1.tgz#78307f539f7b9ca5557babb186ea78ad30cc0375" - integrity sha512-o8lHP20KjIiQe5b/67Rh68xEGRrc2SRsCuuoYclXXoC74AfSRGblU1HKzJWH3HxPZ+Ort85fWHpSX7KwBUC9CQ== + version "3.12.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.4.tgz#93de48bb76bb3ec0fc36563f871ba46e2ee5c7ee" + integrity sha512-L5i5jg/SHkEqzN18gQMTWsZk3KelRsfD1wUVNqtq0kzqWQqcJjyL8yc1o8hJgRrWqrAl2mUFbhfznEIoi7zi2A== uid-number@0.0.6: version "0.0.6" @@ -13702,7 +13757,7 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2: +webpack-dev-middleware@3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== @@ -13713,6 +13768,17 @@ webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2: range-parser "^1.2.1" webpack-log "^2.0.0" +webpack-dev-middleware@^3.7.2: + version "3.7.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" + integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + webpack-dev-server@3.11.0: version "3.11.0" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz#8f154a3bce1bcfd1cc618ef4e703278855e7ff8c" @@ -14015,9 +14081,9 @@ ws@^6.2.1: async-limiter "~1.0.0" ws@^7.0.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.1.tgz#a333be02696bd0e54cea0434e21dcc8a9ac294bb" - integrity sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ== + version "7.4.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.2.tgz#782100048e54eb36fe9843363ab1c68672b261dd" + integrity sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA== xml-name-validator@^3.0.0: version "3.0.0" From 432aac034719cb3679a947320e375cfef7a4303c Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 5 Jan 2021 14:56:04 +0800 Subject: [PATCH 83/83] Use Standby instead of PauseAll method --- .../AbpBackgroundWorkersQuartzModule.cs | 10 +++---- .../Quartz/QuartzBackgroundWorkerAdapter.cs | 2 +- .../Quartz/QuartzBackgroundWorkerManager.cs | 9 ++++-- .../Volo/Abp/Quartz/AbpQuartzModule.cs | 30 ++----------------- 4 files changed, 14 insertions(+), 37 deletions(-) diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/AbpBackgroundWorkersQuartzModule.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/AbpBackgroundWorkersQuartzModule.cs index 9cfc748c4e..a47f8dac77 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/AbpBackgroundWorkersQuartzModule.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/AbpBackgroundWorkersQuartzModule.cs @@ -26,20 +26,20 @@ namespace Volo.Abp.BackgroundWorkers.Quartz public override void OnPreApplicationInitialization(ApplicationInitializationContext context) { - var options = context.ServiceProvider.GetService>().Value; + var options = context.ServiceProvider.GetRequiredService>().Value; if (!options.IsEnabled) { - var quartzOptions = context.ServiceProvider.GetService>().Value; - quartzOptions.StartSchedulerFactory = scheduler => Task.CompletedTask; + var quartzOptions = context.ServiceProvider.GetRequiredService>().Value; + quartzOptions.StartSchedulerFactory = _ => Task.CompletedTask; } } public override void OnApplicationInitialization(ApplicationInitializationContext context) { - var quartzBackgroundWorkerOptions = context.ServiceProvider.GetService>().Value; + var quartzBackgroundWorkerOptions = context.ServiceProvider.GetRequiredService>().Value; if (quartzBackgroundWorkerOptions.IsAutoRegisterEnabled) { - var backgroundWorkerManager = context.ServiceProvider.GetService(); + var backgroundWorkerManager = context.ServiceProvider.GetRequiredService(); var works = context.ServiceProvider.GetServices().Where(x=>x.AutoRegister); foreach (var work in works) diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs index 970beea3f0..0b75f389fe 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs @@ -57,7 +57,7 @@ namespace Volo.Abp.BackgroundWorkers.Quartz .Build(); } - public async override Task Execute(IJobExecutionContext context) + public override async Task Execute(IJobExecutionContext context) { var worker = (IBackgroundWorker) ServiceProvider.GetService(typeof(TWorker)); var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider); diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs index d670c1db98..582a7dd520 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs @@ -19,14 +19,17 @@ namespace Volo.Abp.BackgroundWorkers.Quartz public virtual async Task StartAsync(CancellationToken cancellationToken = default) { - await _scheduler.ResumeAll(cancellationToken); + if (_scheduler.IsStarted && _scheduler.InStandbyMode) + { + await _scheduler.Start(cancellationToken); + } } public virtual async Task StopAsync(CancellationToken cancellationToken = default) { - if (!_scheduler.IsShutdown) + if (_scheduler.IsStarted && !_scheduler.InStandbyMode) { - await _scheduler.PauseAll(cancellationToken); + await _scheduler.Standby(cancellationToken); } } diff --git a/framework/src/Volo.Abp.Quartz/Volo/Abp/Quartz/AbpQuartzModule.cs b/framework/src/Volo.Abp.Quartz/Volo/Abp/Quartz/AbpQuartzModule.cs index 2429f617d9..fc9ba26367 100644 --- a/framework/src/Volo.Abp.Quartz/Volo/Abp/Quartz/AbpQuartzModule.cs +++ b/framework/src/Volo.Abp.Quartz/Volo/Abp/Quartz/AbpQuartzModule.cs @@ -16,9 +16,6 @@ namespace Volo.Abp.Quartz { var options = context.Services.ExecutePreConfiguredActions(); - // TODO: Remove this once Pomelo update MySqlConnector to >= 1.0.0 : https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/pull/1103 - AdaptMysqlConnector(); - context.Services.AddQuartz(options.Properties, build => { // these are the defaults @@ -55,7 +52,7 @@ namespace Volo.Abp.Quartz context.Services.AddSingleton(serviceProvider => { - return AsyncHelper.RunSync(() => serviceProvider.GetService().GetScheduler()); + return AsyncHelper.RunSync(() => serviceProvider.GetRequiredService().GetScheduler()); }); Configure(quartzOptions => @@ -69,7 +66,7 @@ namespace Volo.Abp.Quartz { var options = context.ServiceProvider.GetRequiredService>().Value; - _scheduler = context.ServiceProvider.GetService(); + _scheduler = context.ServiceProvider.GetRequiredService(); AsyncHelper.RunSync(() => options.StartSchedulerFactory.Invoke(_scheduler)); } @@ -81,28 +78,5 @@ namespace Volo.Abp.Quartz AsyncHelper.RunSync(() => _scheduler.Shutdown()); } } - - private void AdaptMysqlConnector() - { - var mySqlAvailable = System.Type.GetType("MySql.Data.MySqlClient.MySqlConnection, MySqlConnector") != null; - if (mySqlAvailable) - { - // Overriding the default 'MySqlConnector' provider to use the old 'MySql.Data' namespace found in MySqlConnector < 1.0.0 - DbProvider.RegisterDbMetadata("MySqlConnector", new DbMetadata() - { - ProductName = "MySQL, MySqlConnector provider", - AssemblyName = "MySqlConnector", - ConnectionType = System.Type.GetType("MySql.Data.MySqlClient.MySqlConnection, MySqlConnector"), - CommandType = System.Type.GetType("MySql.Data.MySqlClient.MySqlCommand, MySqlConnector"), - ParameterType = System.Type.GetType("MySql.Data.MySqlClient.MySqlParameter, MySqlConnector"), - ParameterDbType = System.Type.GetType("MySql.Data.MySqlClient.MySqlDbType, MySqlConnector"), - ParameterDbTypePropertyName = "MySqlDbType", - ParameterNamePrefix = "?", - ExceptionType = System.Type.GetType("MySql.Data.MySqlClient.MySqlException, MySqlConnector"), - BindByName = true, - DbBinaryTypeName = "Blob" - }); - } - } } }