diff --git a/docs/en/Blob-Storing.md b/docs/en/Blob-Storing.md index 1cb8acb78c..2b49a896cd 100644 --- a/docs/en/Blob-Storing.md +++ b/docs/en/Blob-Storing.md @@ -169,7 +169,7 @@ public class ProfileAppService : ApplicationService If you don't use the generic argument and directly inject the `IBlobContainer` (as explained before), you get the default container. Another way of injecting the default container is using `IBlobContainer`, which returns exactly the same container. -The name of the default container is `Default`. +The name of the default container is `default`. ### Named Containers diff --git a/docs/en/Repositories.md b/docs/en/Repositories.md index 86a3e231c5..ff42c6f440 100644 --- a/docs/en/Repositories.md +++ b/docs/en/Repositories.md @@ -126,7 +126,7 @@ You can directly access the data access provider (`DbContext` in this case) to p `IRepository` inherits from `IQueryable`, that means you can **directly use LINQ extension methods** on it, as shown in the example of the "*Generic Repositories*" section above. -**Example: Using the `Where(...)` &and the `ToList()` extension methods** +**Example: Using the `Where(...)` and the `ToList()` extension methods** ````csharp var people = _personRepository diff --git a/docs/zh-Hans/Repositories.md b/docs/zh-Hans/Repositories.md index db4701a573..86d2f2e43d 100644 --- a/docs/zh-Hans/Repositories.md +++ b/docs/zh-Hans/Repositories.md @@ -38,6 +38,8 @@ public class PersonAppService : ApplicationService } ```` +> 参阅 "*IQueryable & 异步操作*" 部分了解如何使用 **异步扩展方法**, 如 `ToListAsync()` (建议始终使用异步) 而不是 `ToList()`. + 在这个例子中; * `PersonAppService` 在它的构造函数中注入了 `IRepository` . @@ -119,4 +121,133 @@ public class PersonRepository : EfCoreRepository, IPe } ```` -你可以直接使用数据库访问提供程序 (本例中是 `DbContext` ) 来执行操作. 有关基于EF Core的自定义仓储的更多信息, 请参阅[EF Core 集成文档](Entity-Framework-Core.md). \ No newline at end of file +你可以直接使用数据库访问提供程序 (本例中是 `DbContext` ) 来执行操作. + +> 请参阅[EF Core](Entity-Framework-Core.md)或[MongoDb](MongoDB.md)了解如何自定义仓储. + +## IQueryable & 异步操作 + +`IRepository` 继承自 `IQueryable`,这意味着你可以**直接使用LINQ扩展方法**. 如上面的*泛型仓储*示例. + +**示例: 使用 `Where(...)` 和 `ToList()` 扩展方法** + +````csharp +var people = _personRepository + .Where(p => p.Name.Contains(nameFilter)) + .ToList(); +```` + +`.ToList`, `Count()`... 是在 `System.Linq` 命名空间下定义的扩展方法. ([参阅所有方法](https://docs.microsoft.com/en-us/dotnet/api/system.linq.queryable)). + +你通常想要使用 `.ToListAsync()`, `.CountAsync()`.... 来编写**真正的异步代码**. + +但在你使用标准的[应用程序启动模板](Startup-Templates/Application.md)时会发现无法在应用层或领域层使用这些异步扩展方法,因为: + +* 这里异步方法**不是标准LINQ方法**,它们定义在[Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore)Nuget包中. +* 标准模板应用层与领域层**不引用**EF Core 包以实现数据库提供程序独立. + +根据你的需求和开发模式,你可以根据以下选项使用异步方法.s + +> 强烈建议使用异步方法! 在执行数据库查询时不要使用同步LINQ方法,以便能够开发可伸缩的应用程序. + +### 选项-1: 引用EF Core + +最简单的方法是在你想要使用异步方法的项目直接引用EF Core包. + +> 添加[Volo.Abp.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore)NuGet包到你的项目间接引用EF Core包. 这可以确保你的应用程序其余部分兼容正确版本的EF Core. + +当你添加NuGet包后,你可以使用全功能的EF Core扩展方法. + +**示例: 直接使用 `ToListAsync()`** + +````csharp +var people = _personRepository + .Where(p => p.Name.Contains(nameFilter)) + .ToListAsync(); +```` + +此方法建议; + +* 如果你正在开发一个应用程序并且**不打算在将来** 更新FE Core,或者如果以后需要更改,你可以**容忍**它. 如果你正在开发最终的应用程序,这是合理的. + +#### MongoDB + +如果使用的是MongoDB,则需要将[Volo.Abp.MongoDB] NuGet包添加到项目中. 但在这种情况下你也不能直接使用异步LINQ扩展(例如`ToListAsync`),因为MongoDB不提供 `IQueryable`的异步扩展方法,而是提供 `IMongoQueryable`. 你需要先将查询强制转换为 `IMongoQueryable` 才能使用异步扩展方法. + +**示例: 转换Cast `IQueryable` 为 `IMongoQueryable` 并且使用 `ToListAsync()`** + +````csharp +var people = ((IMongoQueryable)_personRepository + .Where(p => p.Name.Contains(nameFilter))) + .ToListAsync(); +```` + +### 选项-2: 自定义仓储方法 + +你始终可以创建自定义仓储方法并使用特定数据库提供程序的API,比如这里的异步扩展方法. 有关自定义存储库的更多信息,请参阅[EF Core](Entity-Framework-Core.md)或[MongoDb](MongoDB.md)文档. + +此方法建议; + +* 如果你想**完全隔离**你的领域和应用层和数据库提供程序. +* 如果你开发可**重用的[应用模块](Modules/Index.md)**,并且不想强制使用特定的数据库提供程序,这应该作为一种[最佳实践](Best-Practices/Index.md). + +### 选项-3: IAsyncQueryableExecuter + +> 注意,此功能在ABP框架3.0以之后的版本可用,虽然它也可以用于较早的版本,但它提供的方法非常有限. + +`IAsyncQueryableExecuter` 是一个用于异步执行 `IQueryable` 对象的服务,**不依赖于实际的数据库提供程序**. + +**示例: 注入并使用 `IAsyncQueryableExecuter.ToListAsync()` 方法** + +````csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Linq; + +namespace AbpDemo +{ + public class ProductAppService : ApplicationService, IProductAppService + { + private readonly IRepository _productRepository; + private readonly IAsyncQueryableExecuter _asyncExecuter; + + public ProductAppService( + IRepository productRepository, + IAsyncQueryableExecuter asyncExecuter) + { + _productRepository = productRepository; + _asyncExecuter = asyncExecuter; + } + + public async Task> GetListAsync(string name) + { + //Create the query + var query = _productRepository + .Where(p => p.Name.Contains(name)) + .OrderBy(p => p.Name); + + //Run the query asynchronously + List products = await _asyncExecuter.ToListAsync(query); + + //... + } + } +} +```` + +> `ApplicationService` 和 `DomainService` 基类已经预属性注入了 `AsyncExecuter` 属性,所以你可直接使用. + +ABP框架使用实际数据库提供程序的API异步执行查询.虽然这不是执行查询的常见方式,但它是使用异步API而不依赖于数据库提供者的最佳方式. + +此方法建议; + +* 如果你正在构建一个没有数据库提供程序集成包的**可重用库**,但是在某些情况下需要执行 `IQueryable`对象. + +For example, ABP Framework uses the `IAsyncQueryableExecuter` in the `CrudAppService` base class (see the [application services](Application-Services.md) document). + +例如,ABP框架在 `CrudAppService` 基类中(参阅[应用程序](Application-Services.md)文档)使用 `IAsyncQueryableExecuter`. \ No newline at end of file diff --git a/docs/zh-Hans/SignalR-Integration.md b/docs/zh-Hans/SignalR-Integration.md index 3dea373f5a..5e17b1c75c 100644 --- a/docs/zh-Hans/SignalR-Integration.md +++ b/docs/zh-Hans/SignalR-Integration.md @@ -234,4 +234,5 @@ ABP框架不会更改SignalR. 就像在其他ASP.NET Core应用程序中一样, ## 另请参阅 -* [微软SignalR文档](https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction) \ No newline at end of file +* [微软SignalR文档](https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction) +* [使用ABP,SignalR和RabbitMQ在分布式体系结构中的实时消息传递](https://volosoft.com/blog/RealTime-Messaging-Distributed-Architecture-Abp-SingalR-RabbitMQ) \ No newline at end of file diff --git a/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/DefaultContainer.cs b/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/DefaultContainer.cs index 038d53af6d..278ed46839 100644 --- a/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/DefaultContainer.cs +++ b/framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/DefaultContainer.cs @@ -3,6 +3,6 @@ [BlobContainerName(Name)] public class DefaultContainer { - public const string Name = "Default"; + public const string Name = "default"; } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AbpDistributedEntityEventOptions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AbpDistributedEntityEventOptions.cs new file mode 100644 index 0000000000..19652fca8e --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AbpDistributedEntityEventOptions.cs @@ -0,0 +1,15 @@ +namespace Volo.Abp.Domain.Entities.Events.Distributed +{ + public class AbpDistributedEntityEventOptions + { + public IAutoEntityDistributedEventSelectorList AutoEventSelectors { get; } + + public EtoMappingDictionary EtoMappings { get; set; } + + public AbpDistributedEntityEventOptions() + { + AutoEventSelectors = new AutoEntityDistributedEventSelectorList(); + EtoMappings = new EtoMappingDictionary(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorList.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorList.cs new file mode 100644 index 0000000000..f705f892d5 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorList.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Domain.Entities.Events.Distributed +{ + public class AutoEntityDistributedEventSelectorList : List, IAutoEntityDistributedEventSelectorList + { + public bool RemoveByName(string name) + { + return RemoveAll(s => s.Name == name) > 0; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorListExtensions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorListExtensions.cs new file mode 100644 index 0000000000..e078dfaf43 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/AutoEntityDistributedEventSelectorListExtensions.cs @@ -0,0 +1,78 @@ +using System; +using System.Linq; +using JetBrains.Annotations; + +namespace Volo.Abp.Domain.Entities.Events.Distributed +{ + public static class AutoEntityDistributedEventSelectorListExtensions + { + public const string AllEntitiesSelectorName = "All"; + + public static void AddNamespace([NotNull] this IAutoEntityDistributedEventSelectorList selectors, [NotNull] string namespaceName) + { + Check.NotNull(selectors, nameof(selectors)); + + var selectorName = "Namespace:" + namespaceName; + if (selectors.Any(s => s.Name == selectorName)) + { + return; + } + + selectors.Add( + new NamedTypeSelector( + selectorName, + t => t.FullName?.StartsWith(namespaceName) ?? false + ) + ); + } + + /// + /// Adds a specific entity type and the types derived from that entity type. + /// + /// Type of the entity + public static void Add([NotNull] this IAutoEntityDistributedEventSelectorList selectors) + where TEntity : IEntity + { + Check.NotNull(selectors, nameof(selectors)); + + var selectorName = "Entity:" + typeof(TEntity).FullName; + if (selectors.Any(s => s.Name == selectorName)) + { + return; + } + + selectors.Add( + new NamedTypeSelector( + selectorName, + t => typeof(TEntity).IsAssignableFrom(t) + ) + ); + } + + /// + /// Adds all entity types. + /// + public static void AddAll([NotNull] this IAutoEntityDistributedEventSelectorList selectors) + { + Check.NotNull(selectors, nameof(selectors)); + + if (selectors.Any(s => s.Name == AllEntitiesSelectorName)) + { + return; + } + + selectors.Add( + new NamedTypeSelector( + AllEntitiesSelectorName, + t => typeof(IEntity).IsAssignableFrom(t) + ) + ); + } + + public static bool IsMatch([NotNull] this IAutoEntityDistributedEventSelectorList selectors, Type entityType) + { + Check.NotNull(selectors, nameof(selectors)); + return selectors.Any(s => s.Predicate(entityType)); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityToEtoMapper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityToEtoMapper.cs index 24a757fb08..15a41bad9d 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityToEtoMapper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EntityToEtoMapper.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; -using Volo.Abp.EventBus.Distributed; using Volo.Abp.ObjectMapping; namespace Volo.Abp.Domain.Entities.Events.Distributed @@ -11,10 +10,11 @@ namespace Volo.Abp.Domain.Entities.Events.Distributed public class EntityToEtoMapper : IEntityToEtoMapper, ITransientDependency { protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; } - protected AbpDistributedEventBusOptions Options { get; } + + protected AbpDistributedEntityEventOptions Options { get; } public EntityToEtoMapper( - IOptions options, + IOptions options, IHybridServiceScopeFactory hybridServiceScopeFactory) { HybridServiceScopeFactory = hybridServiceScopeFactory; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/EtoMappingDictionary.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionary.cs similarity index 79% rename from framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/EtoMappingDictionary.cs rename to framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionary.cs index aae99d0cb7..3988ceb3b5 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/EtoMappingDictionary.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionary.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; +using Volo.Abp.EventBus.Distributed; -namespace Volo.Abp.EventBus.Distributed +namespace Volo.Abp.Domain.Entities.Events.Distributed { public class EtoMappingDictionary : Dictionary { diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/EtoMappingDictionaryItem.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionaryItem.cs similarity index 87% rename from framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/EtoMappingDictionaryItem.cs rename to framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionaryItem.cs index d634c44b4d..2550c83a53 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/EtoMappingDictionaryItem.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/EtoMappingDictionaryItem.cs @@ -1,6 +1,6 @@ using System; -namespace Volo.Abp.EventBus.Distributed +namespace Volo.Abp.Domain.Entities.Events.Distributed { public class EtoMappingDictionaryItem { diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/IAutoEntityDistributedEventSelectorList.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/IAutoEntityDistributedEventSelectorList.cs new file mode 100644 index 0000000000..589942e60e --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/Distributed/IAutoEntityDistributedEventSelectorList.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Domain.Entities.Events.Distributed +{ + public interface IAutoEntityDistributedEventSelectorList : IList + { + bool RemoveByName(string name); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs index c9219feffc..cad12b1450 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events.Distributed; @@ -22,13 +23,16 @@ namespace Volo.Abp.Domain.Entities.Events protected IUnitOfWorkManager UnitOfWorkManager { get; } protected IEntityToEtoMapper EntityToEtoMapper { get; } + protected AbpDistributedEntityEventOptions DistributedEntityEventOptions { get; } public EntityChangeEventHelper( IUnitOfWorkManager unitOfWorkManager, - IEntityToEtoMapper entityToEtoMapper) + IEntityToEtoMapper entityToEtoMapper, + IOptions distributedEntityEventOptions) { UnitOfWorkManager = unitOfWorkManager; EntityToEtoMapper = entityToEtoMapper; + DistributedEntityEventOptions = distributedEntityEventOptions.Value; LocalEventBus = NullLocalEventBus.Instance; DistributedEventBus = NullDistributedEventBus.Instance; @@ -65,18 +69,32 @@ namespace Volo.Abp.Domain.Entities.Events false ); - var eto = EntityToEtoMapper.Map(entity); - if (eto != null) + if (ShouldPublishDistributedEventForEntity(entity)) { - await TriggerEventWithEntity( - DistributedEventBus, - typeof(EntityCreatedEto<>), - eto, - false - ); + var eto = EntityToEtoMapper.Map(entity); + if (eto != null) + { + await TriggerEventWithEntity( + DistributedEventBus, + typeof(EntityCreatedEto<>), + eto, + false + ); + } } } + private bool ShouldPublishDistributedEventForEntity(object entity) + { + return DistributedEntityEventOptions + .AutoEventSelectors + .IsMatch( + ProxyHelper + .UnProxy(entity) + .GetType() + ); + } + public virtual async Task TriggerEntityUpdatingEventAsync(object entity) { await TriggerEventWithEntity( @@ -96,15 +114,18 @@ namespace Volo.Abp.Domain.Entities.Events false ); - var eto = EntityToEtoMapper.Map(entity); - if (eto != null) + if (ShouldPublishDistributedEventForEntity(entity)) { - await TriggerEventWithEntity( - DistributedEventBus, - typeof(EntityUpdatedEto<>), - eto, - false - ); + var eto = EntityToEtoMapper.Map(entity); + if (eto != null) + { + await TriggerEventWithEntity( + DistributedEventBus, + typeof(EntityUpdatedEto<>), + eto, + false + ); + } } } @@ -127,15 +148,18 @@ namespace Volo.Abp.Domain.Entities.Events false ); - var eto = EntityToEtoMapper.Map(entity); - if (eto != null) + if (ShouldPublishDistributedEventForEntity(entity)) { - await TriggerEventWithEntity( - DistributedEventBus, - typeof(EntityDeletedEto<>), - EntityToEtoMapper.Map(entity), - false - ); + var eto = EntityToEtoMapper.Map(entity); + if (eto != null) + { + await TriggerEventWithEntity( + DistributedEventBus, + typeof(EntityDeletedEto<>), + eto, + false + ); + } } } diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/AbpDistributedEventBusOptions.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/AbpDistributedEventBusOptions.cs index 1d1d7768f2..342e7b77bb 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/AbpDistributedEventBusOptions.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/AbpDistributedEventBusOptions.cs @@ -5,12 +5,10 @@ namespace Volo.Abp.EventBus.Distributed public class AbpDistributedEventBusOptions { public ITypeList Handlers { get; } - public EtoMappingDictionary EtoMappings { get; set; } public AbpDistributedEventBusOptions() { Handlers = new TypeList(); - EtoMappings = new EtoMappingDictionary(); } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs index 683c99d417..41079bfa9e 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/TestAppModule.cs @@ -4,7 +4,7 @@ using Volo.Abp.Autofac; using Volo.Abp.Modularity; using Volo.Abp.TestApp.Domain; using Volo.Abp.AutoMapper; -using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.TestApp.Application.Dto; using Volo.Abp.Threading; @@ -45,8 +45,9 @@ namespace Volo.Abp.TestApp private void ConfigureDistributedEventBus() { - Configure(options => + Configure(options => { + options.AutoEventSelectors.Add(); options.EtoMappings.Add(); }); } diff --git a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs index f39c4c88fb..3179303215 100644 --- a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs +++ b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDomainModule.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AutoMapper; using Volo.Abp.Domain; -using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Modularity; using Volo.Blogging.Blogs; using Volo.Blogging.Comments; @@ -25,7 +25,7 @@ namespace Volo.Blogging options.AddProfile(validate: true); }); - Configure(options => + Configure(options => { options.EtoMappings.Add(typeof(BloggingDomainModule)); options.EtoMappings.Add(typeof(BloggingDomainModule)); diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/GetAllInput.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/GetAllInput.cs index ced1c1ceda..e375f6ba0b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/GetAllInput.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/GetAllInput.cs @@ -12,10 +12,28 @@ namespace Volo.Docs.Admin.Documents [StringLength(DocumentConsts.MaxNameLength)] public string Name { get; set; } + [StringLength(DocumentConsts.MaxVersionNameLength)] + public string Version { get; set; } + [StringLength(DocumentConsts.MaxLanguageCodeNameLength)] public string LanguageCode { get; set; } - [StringLength(DocumentConsts.MaxVersionNameLength)] - public string Version { get; set; } + [StringLength(DocumentConsts.MaxFileNameNameLength)] + public string FileName { get; set; } + + [StringLength(DocumentConsts.MaxFormatNameLength)] + public string Format { get; set; } + + public DateTime? CreationTimeMin { get; set; } + public DateTime? CreationTimeMax { get; set; } + + public DateTime? LastUpdatedTimeMin { get; set; } + public DateTime? LastUpdatedTimeMax { get; set; } + + public DateTime? LastSignificantUpdateTimeMin { get; set; } + public DateTime? LastSignificantUpdateTimeMax { get; set; } + + public DateTime? LastCachedTimeMin { get; set; } + public DateTime? LastCachedTimeMax { get; set; } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json index 32d0b3bc27..b73f43317c 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json @@ -43,6 +43,16 @@ "ReIndexDocumentConfirmation": "Are you sure you want to reindex this item?", "DeleteDocumentFromDbConfirmation": "Are you sure you want to delete this item from database?", "DeleteFromDatabase": "Delete from database", - "Deleted": "Deleted" + "Deleted": "Deleted", + "Search": "Search", + "StartDate": "Start date", + "EndDate": "End date", + "CreationTime": "Creation time", + "LastUpdateTime": "Last update", + "LastSignificantUpdateTime": "Last significant update", + "Version": "Version", + "LanguageCode": "Language code", + "FileName": "File name", + "LastCachedTime": "Cache time" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs index 0868e9eb80..cb6443d268 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs @@ -137,20 +137,40 @@ namespace Volo.Docs.Admin.Documents public async Task> GetAllAsync(GetAllInput input) { var totalCount = await _documentRepository.GetAllCountAsync( - projectId: input.ProjectId, - name: input.Name, - version: input.Version, - languageCode: input.LanguageCode, - sorting: input.Sorting, - maxResultCount: input.MaxResultCount, - skipCount: input.SkipCount - ); + projectId: input.ProjectId, + name: input.Name, + version: input.Version, + languageCode: input.LanguageCode, + fileName: input.FileName, + format: input.Format, + creationTimeMin: input.CreationTimeMin, + creationTimeMax: input.CreationTimeMax, + lastUpdatedTimeMin: input.LastUpdatedTimeMin, + lastUpdatedTimeMax: input.LastUpdatedTimeMax, + lastSignificantUpdateTimeMin: input.LastSignificantUpdateTimeMin, + lastSignificantUpdateTimeMax: input.LastSignificantUpdateTimeMax, + lastCachedTimeMin: input.LastCachedTimeMin, + lastCachedTimeMax: input.LastCachedTimeMax, + sorting: input.Sorting, + maxResultCount: input.MaxResultCount, + skipCount: input.SkipCount + ); var docs = await _documentRepository.GetAllAsync( projectId: input.ProjectId, name: input.Name, version: input.Version, languageCode: input.LanguageCode, + fileName: input.FileName, + format: input.Format, + creationTimeMin: input.CreationTimeMin, + creationTimeMax: input.CreationTimeMax, + lastUpdatedTimeMin: input.LastUpdatedTimeMin, + lastUpdatedTimeMax: input.LastUpdatedTimeMax, + lastSignificantUpdateTimeMin: input.LastSignificantUpdateTimeMin, + lastSignificantUpdateTimeMax: input.LastSignificantUpdateTimeMax, + lastCachedTimeMin: input.LastCachedTimeMin, + lastCachedTimeMax: input.LastCachedTimeMax, sorting: input.Sorting, maxResultCount: input.MaxResultCount, skipCount: input.SkipCount diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml index 876d475dfc..1afd658afe 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml @@ -22,31 +22,194 @@ } - - - -

Filters ...

- @* - - *@ -
-
- - - - - @L["Actions"] - @L["Name"] - @L["Version"] - @L["LanguageCode"] - @L["FileName"] - @L["Format"] - @L["CreationTime"] - @L["LastUpdatedTime"] - @L["LastSignificantUpdateTime"] - @L["LastCachedTime"] - - - - -
+@section styles { + +} + +
+ + +
+ +
+
+
+
+
@L["Name"].Value
+
+ + +
+
+ +
+
+
+
@L["Version"].Value
+
+ + +
+
+ +
+
+
+
@L["LanguageCode"].Value
+
+ + +
+
+ + +
+
+
+
@L["FileName"].Value
+
+ + +
+
+ +
+
+
+
@L["Format"].Value
+
+ + +
+
+ + +
+
+
+
@L["CreationTime"].Value
+
+ + + + - + + +
+
+ +
+
+
+
@L["LastUpdateTime"].Value
+
+ + + + - + + +
+
+ +
+
+
+
@L["LastSignificantUpdateTime"].Value
+
+ + + + - + + +
+
+ +
+
+
+
@L["LastCachedTime"].Value
+
+ + + + - + + +
+
+ +
+ +
+
+
+
+ + + + + @L["Actions"] + @L["Name"] + @L["Version"] + @L["LanguageCode"] + @L["FileName"] + @L["Format"] + @L["CreationTime"] + @L["LastUpdatedTime"] + @L["LastSignificantUpdateTime"] + @L["LastCachedTime"] + + + + +
+
\ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs index def325bd0d..559eaab5eb 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs @@ -1,6 +1,9 @@ +using System; +using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Volo.Docs.Documents; namespace Volo.Docs.Admin.Pages.Docs.Admin.Documents { diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.css b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.css new file mode 100644 index 0000000000..006512da9a --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.css @@ -0,0 +1,3 @@ +#DocumentsContainer .datepicker { + display: inline-block !important; + width: 7rem !important; } diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js index ed5e5793de..dc77bbc687 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js @@ -1,8 +1,32 @@ $(function () { var l = abp.localization.getResource('Docs'); + var service = window.volo.docs.admin.documentsAdmin; - var _dataTable = $('#DocumentsTable').DataTable(abp.libs.datatables.normalizeConfiguration({ + var getFormattedDate = function ($datePicker) { + return $datePicker.data().datepicker.getFormattedDate("yyyy-mm-dd"); + }; + + var getFilter = function () { + return { + projectId: $("#ProjectId").val(), + name: $("#Name").val(), + version: $("#Version").val(), + languageCode: $("#LanguageCode").val(), + fileName: $("#FileName").val(), + format: $("#Format").val(), + creationTimeMin: getFormattedDate($("#CreationTimeMin")), + creationTimeMax: getFormattedDate($("#CreationTimeMax")), + lastUpdatedTimeMin: getFormattedDate($("#LastUpdatedTimeMin")), + lastUpdatedTimeMax: getFormattedDate($("#LastUpdatedTimeMax")), + lastSignificantUpdateTimeMin: getFormattedDate($("#LastSignificantUpdateTimeMin")), + lastSignificantUpdateTimeMax: getFormattedDate($("#LastSignificantUpdateTimeMax")), + lastCachedTimeMin: getFormattedDate($("#LastCachedTimeMin")), + lastCachedTimeMax: getFormattedDate($("#LastCachedTimeMax")) + }; + }; + + var dataTable = $('#DocumentsTable').DataTable(abp.libs.datatables.normalizeConfiguration({ processing: true, serverSide: true, scrollX: true, @@ -10,7 +34,7 @@ searching: false, autoWidth: false, scrollCollapse: true, - ajax: abp.libs.datatables.createAjax(volo.docs.admin.documentsAdmin.getAll), + ajax: abp.libs.datatables.createAjax(service.getAll, getFilter), columnDefs: [ { rowAction: { @@ -21,11 +45,10 @@ visible: abp.auth.isGranted('Docs.Admin.Documents'), confirmMessage: function (data) { return l('RemoveFromCacheConfirmation'); }, action: function (data) { - volo.docs.admin.documentsAdmin - .removeFromCache(data.record.id) + service.removeFromCache(data.record.id) .then(function () { abp.message.success(l('RemovedFromCache')); - _dataTable.ajax.reload(); + dataTable.ajax.reload(); }); } }, @@ -34,11 +57,10 @@ visible: abp.auth.isGranted('Docs.Admin.Documents'), confirmMessage: function (data) { return l('ReIndexDocumentConfirmation'); }, action: function (data) { - volo.docs.admin.documentsAdmin - .reindex(data.record.id) + service.reindex(data.record.id) .then(function () { abp.message.success(l('ReindexCompleted')); - _dataTable.ajax.reload(); + dataTable.ajax.reload(); }); } }, @@ -47,11 +69,10 @@ visible: abp.auth.isGranted('Docs.Admin.Documents'), confirmMessage: function (data) { return l('DeleteDocumentFromDbConfirmation'); }, action: function (data) { - volo.docs.admin.documentsAdmin - .deleteFromDatabase(data.record.id) + service.deleteFromDatabase(data.record.id) .then(function () { abp.message.success(l('Deleted')); - _dataTable.ajax.reload(); + dataTable.ajax.reload(); }); } } @@ -76,14 +97,7 @@ }, { target: 5, - data: "format", - render: function (data) { - if (data === 'md') { - return 'markdown'; - } - - return data; - } + data: "format" }, { target: 6, @@ -136,18 +150,15 @@ ] })); + $("#FilterForm input[type='text']").keypress(function (e) { + if (e.which === 13) { + dataTable.ajax.reload(); + } + }); - $("#ReIndexAllProjects").click(function (event) { - abp.message.confirm(l('ReIndexAllProjectConfirmationMessage')) - .done(function (accepted) { - if (accepted) { - volo.docs.admin.projectsAdmin - .reindexAll() - .then(function () { - abp.message.success(l('SuccessfullyReIndexAllProject')); - }); - } - }); + $("#SearchButton").click(function (e) { + e.preventDefault(); + dataTable.ajax.reload(); }); }); diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.min.css b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.min.css new file mode 100644 index 0000000000..f98ba4beab --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.min.css @@ -0,0 +1 @@ +#DocumentsContainer .datepicker{display:inline-block !important;width:7rem !important;} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.scss b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.scss new file mode 100644 index 0000000000..97147313df --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.scss @@ -0,0 +1,6 @@ +#DocumentsContainer { + .datepicker { + display: inline-block !important; + width: 7rem !important; + } +} diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj b/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj index 3098bab9d0..164c28cdb2 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj +++ b/modules/docs/src/Volo.Docs.Admin.Web/Volo.Docs.Admin.Web.csproj @@ -13,13 +13,16 @@ 2.8 + + + + - @@ -29,8 +32,7 @@ - - + diff --git a/modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json b/modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json new file mode 100644 index 0000000000..32ae3754e2 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json @@ -0,0 +1,6 @@ +[ + { + "outputFile": "Pages/Docs/Admin/Documents/index.css", + "inputFile": "Pages/Docs/Admin/Documents/index.scss" + } +] \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json.defaults b/modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json.defaults new file mode 100644 index 0000000000..b3519312c4 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Web/compilerconfig.json.defaults @@ -0,0 +1,63 @@ +{ + "compilers": { + "less": { + "autoPrefix": "", + "cssComb": "none", + "ieCompat": true, + "strictMath": false, + "strictUnits": false, + "relativeUrls": true, + "rootPath": "", + "sourceMapRoot": "", + "sourceMapBasePath": "", + "sourceMap": false + }, + "sass": { + "autoPrefix": "", + "includePath": "", + "indentType": "space", + "indentWidth": 2, + "outputStyle": "nested", + "Precision": 5, + "relativeUrls": true, + "sourceMapRoot": "", + "lineFeed": "", + "sourceMap": false + }, + "stylus": { + "sourceMap": false + }, + "babel": { + "sourceMap": false + }, + "coffeescript": { + "bare": false, + "runtimeMode": "node", + "sourceMap": false + }, + "handlebars": { + "root": "", + "noBOM": false, + "name": "", + "namespace": "", + "knownHelpersOnly": false, + "forcePartial": false, + "knownHelpers": [], + "commonjs": "", + "amd": false, + "sourceMap": false + } + }, + "minifiers": { + "css": { + "enabled": true, + "termSemicolons": true, + "gzip": false + }, + "javascript": { + "enabled": true, + "termSemicolons": true, + "gzip": false + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs index 5e53b858ce..ecc52d1f26 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/DocsDomainModule.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Options; using Volo.Abp; using Volo.Abp.AutoMapper; using Volo.Abp.Domain; -using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.Threading; @@ -34,7 +34,7 @@ namespace Volo.Docs options.AddProfile(validate: true); }); - Configure(options => + Configure(options => { options.EtoMappings.Add(typeof(DocsDomainModule)); options.EtoMappings.Add(typeof(DocsDomainModule)); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentRepository.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentRepository.cs index c09cb261ec..3773775b88 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentRepository.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentRepository.cs @@ -23,10 +23,21 @@ namespace Volo.Docs.Documents string version, CancellationToken cancellationToken = default); - Task> GetAllAsync(Guid? projectId, + Task> GetAllAsync( + Guid? projectId, string name, string version, string languageCode, + string fileName, + string format, + DateTime? creationTimeMin, + DateTime? creationTimeMax, + DateTime? lastUpdatedTimeMin, + DateTime? lastUpdatedTimeMax, + DateTime? lastSignificantUpdateTimeMin, + DateTime? lastSignificantUpdateTimeMax, + DateTime? lastCachedTimeMin, + DateTime? lastCachedTimeMax, string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, @@ -37,6 +48,16 @@ namespace Volo.Docs.Documents string name, string version, string languageCode, + string fileName, + string format, + DateTime? creationTimeMin, + DateTime? creationTimeMax, + DateTime? lastUpdatedTimeMin, + DateTime? lastUpdatedTimeMax, + DateTime? lastSignificantUpdateTimeMin, + DateTime? lastSignificantUpdateTimeMax, + DateTime? lastCachedTimeMin, + DateTime? lastCachedTimeMax, string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, 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 46145043b1..f096bc10d9 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 @@ -24,16 +24,44 @@ namespace Volo.Docs.Documents return await DbSet.Where(d => d.ProjectId == projectId).ToListAsync(cancellationToken: cancellationToken); } - public async Task> GetAllAsync(Guid? projectId, + public async Task> GetAllAsync( + Guid? projectId, string name, string version, string languageCode, + string fileName, + string format, + DateTime? creationTimeMin, + DateTime? creationTimeMax, + DateTime? lastUpdatedTimeMin, + DateTime? lastUpdatedTimeMax, + DateTime? lastSignificantUpdateTimeMin, + DateTime? lastSignificantUpdateTimeMax, + DateTime? lastCachedTimeMin, + DateTime? lastCachedTimeMax, string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, CancellationToken cancellationToken = default) { - var query = ApplyFilterForGetAll(DbSet, projectId, name, version, languageCode); + var query = ApplyFilterForGetAll( + DbSet, + projectId: projectId, + name: name, + version: version, + languageCode: languageCode, + format: format, + fileName: fileName, + creationTimeMin: creationTimeMin, + creationTimeMax: creationTimeMax, + lastUpdatedTimeMin: lastUpdatedTimeMin, + lastUpdatedTimeMax: lastUpdatedTimeMax, + lastSignificantUpdateTimeMin: lastSignificantUpdateTimeMin, + lastSignificantUpdateTimeMax: lastSignificantUpdateTimeMax, + lastCachedTimeMin: lastCachedTimeMin, + lastCachedTimeMax: lastCachedTimeMax + ); + query = query.OrderBy(string.IsNullOrWhiteSpace(sorting) ? nameof(Document.Name) : sorting); return await query.PageBy(skipCount, maxResultCount).ToListAsync(cancellationToken); } @@ -43,12 +71,39 @@ namespace Volo.Docs.Documents string name, string version, string languageCode, + string fileName, + string format, + DateTime? creationTimeMin, + DateTime? creationTimeMax, + DateTime? lastUpdatedTimeMin, + DateTime? lastUpdatedTimeMax, + DateTime? lastSignificantUpdateTimeMin, + DateTime? lastSignificantUpdateTimeMax, + DateTime? lastCachedTimeMin, + DateTime? lastCachedTimeMax, string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, CancellationToken cancellationToken = default) { - var query = ApplyFilterForGetAll(DbSet, projectId, name, version, languageCode); + var query = ApplyFilterForGetAll( + DbSet, + projectId: projectId, + name: name, + version: version, + languageCode: languageCode, + format: format, + fileName: fileName, + creationTimeMin: creationTimeMin, + creationTimeMax: creationTimeMax, + lastUpdatedTimeMin: lastUpdatedTimeMin, + lastUpdatedTimeMax: lastUpdatedTimeMax, + lastSignificantUpdateTimeMin: lastSignificantUpdateTimeMin, + lastSignificantUpdateTimeMax: lastSignificantUpdateTimeMax, + lastCachedTimeMin: lastCachedTimeMin, + lastCachedTimeMax: lastCachedTimeMax + ); + return await query.LongCountAsync(GetCancellationToken(cancellationToken)); } @@ -81,13 +136,47 @@ namespace Volo.Docs.Documents string name, string version, string languageCode, + string fileName, + string format, + DateTime? creationTimeMin, + DateTime? creationTimeMax, + DateTime? lastUpdatedTimeMin, + DateTime? lastUpdatedTimeMax, + DateTime? lastSignificantUpdateTimeMin, + DateTime? lastSignificantUpdateTimeMax, + DateTime? lastCachedTimeMin, + DateTime? lastCachedTimeMax, CancellationToken cancellationToken = default) { return DbSet - .WhereIf(projectId.HasValue, d => d.ProjectId == projectId.Value) - .WhereIf(name != null, d => d.Name != null && d.Name.Contains(name)) - .WhereIf(version != null, d => d.Version != null && d.Version == version) - .WhereIf(languageCode != null, d => d.LanguageCode != null && d.LanguageCode == languageCode); + .WhereIf(projectId.HasValue, + d => d.ProjectId == projectId.Value) + .WhereIf(name != null, + d => d.Name != null && d.Name.Contains(name)) + .WhereIf(version != null, + d => d.Version != null && d.Version == version) + .WhereIf(languageCode != null, + d => d.LanguageCode != null && d.LanguageCode == languageCode) + .WhereIf(fileName != null, + d => d.FileName != null && d.FileName.Contains(fileName)) + .WhereIf(format != null, + d => d.Format != null && d.Format == format) + .WhereIf(creationTimeMin.HasValue, + d => d.CreationTime.Date >= creationTimeMin.Value.Date) + .WhereIf(creationTimeMax.HasValue, + d => d.CreationTime.Date <= creationTimeMax.Value.Date) + .WhereIf(lastUpdatedTimeMin.HasValue, + d => d.LastUpdatedTime.Date >= lastUpdatedTimeMin.Value.Date) + .WhereIf(lastUpdatedTimeMax.HasValue, + d => d.LastUpdatedTime.Date <= lastUpdatedTimeMax.Value.Date) + .WhereIf(lastSignificantUpdateTimeMin.HasValue, + d => d.LastSignificantUpdateTime != null && d.LastSignificantUpdateTime.Value.Date >= lastSignificantUpdateTimeMin.Value.Date) + .WhereIf(lastSignificantUpdateTimeMax.HasValue, + d => d.LastSignificantUpdateTime != null && d.LastSignificantUpdateTime.Value.Date <= lastSignificantUpdateTimeMax.Value.Date) + .WhereIf(lastCachedTimeMin.HasValue, + d => d.LastCachedTime.Date >= lastCachedTimeMin.Value.Date) + .WhereIf(lastCachedTimeMax.HasValue, + d => d.LastCachedTime.Date <= lastCachedTimeMax.Value.Date); } } } \ 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 78710e553e..b3b5210986 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 @@ -43,33 +43,88 @@ namespace Volo.Docs.Documents x.Version == version, cancellationToken: cancellationToken); } - public async Task> GetAllAsync(Guid? projectId, + public async Task> GetAllAsync( + Guid? projectId, string name, string version, string languageCode, + string fileName, + string format, + DateTime? creationTimeMin, + DateTime? creationTimeMax, + DateTime? lastUpdatedTimeMin, + DateTime? lastUpdatedTimeMax, + DateTime? lastSignificantUpdateTimeMin, + DateTime? lastSignificantUpdateTimeMax, + DateTime? lastCachedTimeMin, + DateTime? lastCachedTimeMax, string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, CancellationToken cancellationToken = default) { + return await - ApplyFilterForGetAll(GetMongoQueryable(), projectId, name, version, languageCode) - .OrderBy(string.IsNullOrWhiteSpace(sorting) ? "name asc" : sorting).As>() - .PageBy>(skipCount, maxResultCount) - .ToListAsync(GetCancellationToken(cancellationToken)); + ApplyFilterForGetAll( + GetMongoQueryable(), + projectId: projectId, + name: name, + version: version, + languageCode: languageCode, + format: format, + fileName: fileName, + creationTimeMin: creationTimeMin, + creationTimeMax: creationTimeMax, + lastUpdatedTimeMin: lastUpdatedTimeMin, + lastUpdatedTimeMax: lastUpdatedTimeMax, + lastSignificantUpdateTimeMin: lastSignificantUpdateTimeMin, + lastSignificantUpdateTimeMax: lastSignificantUpdateTimeMax, + lastCachedTimeMin: lastCachedTimeMin, + lastCachedTimeMax: lastCachedTimeMax) + .OrderBy(string.IsNullOrWhiteSpace(sorting) ? "name asc" : sorting).As>() + .PageBy>(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); } - public async Task GetAllCountAsync(Guid? projectId, + public async Task GetAllCountAsync( + Guid? projectId, string name, string version, string languageCode, + string fileName, + string format, + DateTime? creationTimeMin, + DateTime? creationTimeMax, + DateTime? lastUpdatedTimeMin, + DateTime? lastUpdatedTimeMax, + DateTime? lastSignificantUpdateTimeMin, + DateTime? lastSignificantUpdateTimeMax, + DateTime? lastCachedTimeMin, + DateTime? lastCachedTimeMax, string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, CancellationToken cancellationToken = default) { + + return await - ApplyFilterForGetAll(GetMongoQueryable(), projectId, name, version, languageCode) + ApplyFilterForGetAll( + GetMongoQueryable(), + projectId: projectId, + name: name, + version: version, + languageCode: languageCode, + format: format, + fileName: fileName, + creationTimeMin: creationTimeMin, + creationTimeMax: creationTimeMax, + lastUpdatedTimeMin: lastUpdatedTimeMin, + lastUpdatedTimeMax: lastUpdatedTimeMax, + lastSignificantUpdateTimeMin: lastSignificantUpdateTimeMin, + lastSignificantUpdateTimeMax: lastSignificantUpdateTimeMax, + lastCachedTimeMin: lastCachedTimeMin, + lastCachedTimeMax: lastCachedTimeMax) .OrderBy(string.IsNullOrWhiteSpace(sorting) ? "name asc" : sorting).As>() .PageBy>(skipCount, maxResultCount) .LongCountAsync(GetCancellationToken(cancellationToken)); @@ -86,6 +141,16 @@ namespace Volo.Docs.Documents string name, string version, string languageCode, + string fileName, + string format, + DateTime? creationTimeMin, + DateTime? creationTimeMax, + DateTime? lastUpdatedTimeMin, + DateTime? lastUpdatedTimeMax, + DateTime? lastSignificantUpdateTimeMin, + DateTime? lastSignificantUpdateTimeMax, + DateTime? lastCachedTimeMin, + DateTime? lastCachedTimeMax, CancellationToken cancellationToken = default) { if (projectId.HasValue) @@ -108,6 +173,51 @@ namespace Volo.Docs.Documents query = query.Where(d => d.LanguageCode != null && d.LanguageCode == languageCode); } + if (fileName != null) + { + query = query.Where(d => d.FileName != null && d.FileName.Contains(fileName)); + } + + if (creationTimeMin.HasValue) + { + query = query.Where(d => d.CreationTime.Date >= creationTimeMin.Value.Date); + } + + if (creationTimeMax.HasValue) + { + query = query.Where(d => d.CreationTime.Date <= creationTimeMax.Value.Date); + } + + if (lastUpdatedTimeMin.HasValue) + { + query = query.Where(d => d.LastUpdatedTime.Date >= lastUpdatedTimeMin.Value.Date); + } + + if (lastUpdatedTimeMax.HasValue) + { + query = query.Where(d => d.LastUpdatedTime.Date <= lastUpdatedTimeMax.Value.Date); + } + + if (lastSignificantUpdateTimeMin.HasValue) + { + query = query.Where(d => d.LastSignificantUpdateTime != null && d.LastSignificantUpdateTime.Value.Date >= lastSignificantUpdateTimeMin.Value.Date); + } + + if (lastSignificantUpdateTimeMax.HasValue) + { + query = query.Where(d => d.LastSignificantUpdateTime != null && d.LastSignificantUpdateTime.Value.Date <= lastSignificantUpdateTimeMax.Value.Date); + } + + if (lastCachedTimeMin.HasValue) + { + query = query.Where(d => d.LastCachedTime.Date >= lastCachedTimeMin.Value.Date); + } + + if (lastCachedTimeMax.HasValue) + { + query = query.Where(d => d.LastCachedTime.Date <= lastCachedTimeMax.Value.Date); + } + return query; } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs index f757c56f1e..07c4d2e971 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using Volo.Abp.AutoMapper; using Volo.Abp.Domain; -using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Modularity; using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectExtending.Modularity; @@ -29,7 +29,7 @@ namespace Volo.Abp.Identity options.AddProfile(validate: true); }); - Configure(options => + Configure(options => { options.EtoMappings.Add(typeof(AbpIdentityDomainModule)); options.EtoMappings.Add(typeof(AbpIdentityDomainModule)); diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs index d9fb330a02..ccfbb85359 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityDomainTestModule.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.Identity; @@ -14,6 +15,14 @@ namespace Volo.Abp.Identity )] public class AbpIdentityDomainTestModule : AbpModule { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.AutoEventSelectors.Add(); + }); + } + public override void OnApplicationInitialization(ApplicationInitializationContext context) { SeedTestData(context); diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs index 95e8f925c4..b3fc9b1ba3 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_User_Change_Event_Tests.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Shouldly; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus.Distributed; using Volo.Abp.Testing.Utils; using Volo.Abp.Uow; @@ -28,11 +29,17 @@ namespace Volo.Abp.Identity } [Fact] - public async Task Should_Register_Handler() + public void Should_Register_Handler() { - var options = GetRequiredService>().Value; - options.EtoMappings.ShouldContain(m => m.Key == typeof(IdentityUser) && m.Value.EtoType == typeof(UserEto)); - options.Handlers.ShouldContain(h => h == typeof(DistributedUserUpdateHandler)); + GetRequiredService>() + .Value + .EtoMappings + .ShouldContain(m => m.Key == typeof(IdentityUser) && m.Value.EtoType == typeof(UserEto)); + + GetRequiredService>() + .Value + .Handlers + .ShouldContain(h => h == typeof(DistributedUserUpdateHandler)); } [Fact] diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs index 01001aeb35..9e36576e56 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.AutoMapper; using Volo.Abp.BackgroundWorkers; using Volo.Abp.Caching; -using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Identity; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; @@ -41,7 +41,7 @@ namespace Volo.Abp.IdentityServer options.AddProfile(validate: true); }); - Configure(options => + Configure(options => { options.EtoMappings.Add(typeof(AbpIdentityServerDomainModule)); options.EtoMappings.Add(typeof(AbpIdentityServerDomainModule)); diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs index f882f8659e..5bf2aeb0b9 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs @@ -2,7 +2,7 @@ using Volo.Abp.AutoMapper; using Volo.Abp.Data; using Volo.Abp.Domain; -using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; using Volo.Abp.UI; @@ -26,7 +26,7 @@ namespace Volo.Abp.TenantManagement options.AddProfile(validate: true); }); - Configure(options => + Configure(options => { options.EtoMappings.Add(); }); diff --git a/npm/ng-packs/packages/core/src/lib/services/list.service.ts b/npm/ng-packs/packages/core/src/lib/services/list.service.ts index 3aff601f7a..d3da082eeb 100644 --- a/npm/ng-packs/packages/core/src/lib/services/list.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/list.service.ts @@ -1,6 +1,6 @@ import { Inject, Injectable, OnDestroy, Optional } from '@angular/core'; -import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs'; -import { debounceTime, shareReplay, switchMap, tap } from 'rxjs/operators'; +import { BehaviorSubject, Observable, of, ReplaySubject } from 'rxjs'; +import { catchError, debounceTime, filter, shareReplay, switchMap, tap } from 'rxjs/operators'; import { ABP } from '../models/common'; import { PagedResultDto } from '../models/dtos'; import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token'; @@ -88,7 +88,8 @@ export class ListService implements OnDes this._isLoading$.next(true); return this.query$.pipe( - switchMap(streamCreatorCallback), + switchMap(query => streamCreatorCallback(query).pipe(catchError(() => of(null)))), + filter(Boolean), tap(() => this._isLoading$.next(false)), shareReplay({ bufferSize: 1, refCount: true }), takeUntilDestroy(this), diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts index 85e574d63d..a16925ebd7 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-list.directive.ts @@ -36,8 +36,15 @@ export class NgxDatatableListDirective implements OnChanges, OnDestroy, OnInit { private subscribeToSort() { const sub = this.table.sort.subscribe(({ sorts: [{ prop, dir }] }) => { - this.list.sortKey = prop; - this.list.sortOrder = dir; + if (prop === this.list.sortKey && this.list.sortOrder === 'desc') { + this.list.sortKey = ''; + this.list.sortOrder = ''; + this.table.sorts = []; + this.cdRef.detectChanges(); + } else { + this.list.sortKey = prop; + this.list.sortOrder = dir; + } }); this.subscription.add(sub); } @@ -45,7 +52,7 @@ export class NgxDatatableListDirective implements OnChanges, OnDestroy, OnInit { private subscribeToIsLoading() { const sub = this.list.isLoading$.subscribe(loading => { this.table.loadingIndicator = loading; - this.cdRef.markForCheck(); + this.cdRef.detectChanges(); }); this.subscription.add(sub); } diff --git a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs index b351a33fb6..a8c5d58ac4 100644 --- a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs +++ b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/BackendAdminAppHostModule.cs @@ -8,7 +8,6 @@ using ProductManagement; using StackExchange.Redis; using Microsoft.OpenApi.Models; using MsDemo.Shared; -using Swashbuckle.AspNetCore.Swagger; using Volo.Abp; using Volo.Abp.AspNetCore.Authentication.OAuth; using Volo.Abp.AspNetCore.Mvc.Client; diff --git a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs index 9b96532e4c..83317c3f0f 100644 --- a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs @@ -13,6 +13,7 @@ using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Auditing; using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.Autofac; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.SqlServer; using Volo.Abp.EventBus.RabbitMq; @@ -77,6 +78,11 @@ namespace IdentityService.Host { options.UseSqlServer(); }); + + Configure(options => + { + options.AutoEventSelectors.Add(); + }); context.Services.AddStackExchangeRedisCache(options => {